# Diller Tap2ID — POS Integration Guide
Edited
# Diller Tap2ID — POS Integration Guide
## Table of Contents
1. [Introduction](#introduction)
2. [How Tap2ID Works](#how-tap2id-works)
3. [Tap2ID with Nets (Baxi.NET)](#tap2id-with-nets-baxinet)
- [Prerequisites](#baxi-prerequisites)
- [Step 1: Read Card & Identify Member (SendJson)](#baxi-step-1-read-card--identify-member)
- [Step 2: Query Diller for Member Details & Benefits](#baxi-step-2-query-diller-for-member-details)
- [Step 3: Apply Discounts & Process Payment (TransferAmount)](#baxi-step-3-process-payment)
- [Registering a New Card (InsertAsset)](#baxi-registering-a-new-card)
4. [Tap2ID with Verifone](#tap2id-with-verifone)
- [Prerequisites](#verifone-prerequisites)
- [Step 1: Read Card & Get Token (Card Acquisition)](#verifone-step-1-card-acquisition)
- [Step 2: Query Diller for Member Details & Benefits](#verifone-step-2-query-diller-for-member-details)
- [Step 3: Apply Discounts & Process Payment](#verifone-step-3-process-payment)
- [Registering a New Card](#verifone-registering-a-new-card)
5. [Diller API Reference](#diller-api-reference)
- [Authentication](#authentication)
- [Identify Member by Card Token](#identify-member-by-card-token)
- [Search Member by Phone](#search-member-by-phone)
- [Get Member Coupons](#get-member-coupons)
- [Register Card to Member](#register-card-to-member)
- [Enroll New Member](#enroll-new-member)
- [Create Transaction](#create-transaction)
6. [Key Differences: Nets vs Verifone](#key-differences)
7. [Complete Flow Diagrams](#complete-flow-diagrams)
8. [FAQ & Troubleshooting](#faq--troubleshooting)
---
## Introduction
**Tap2ID** allows loyalty members to identify themselves at the point of sale by simply tapping their payment card on the terminal — no phone number, no app, no barcode needed. The POS reads the card, matches it to a Diller loyalty member, fetches their coupons and benefits, applies discounts to the basket, and then charges the final amount — all in a seamless checkout experience.
This guide covers how to integrate Tap2ID into your POS system using two terminal families:
| Terminal | SDK | Card Identification Method |
|----------|-----|--------------------------|
| **Nets (Ingenico/Baxi)** | BAXI.NET SDK (`baxi_dotnet.dll`) | SendJson with DAM/Storebox |
| **Verifone P630** | PaymentSdk (PSDK) | Card Acquisition with tokenization |
Both follow the same high-level flow but use different SDK calls to obtain the card identifier.
---
## How Tap2ID Works
The checkout flow with Tap2ID follows these steps:
```
┌─────────────────────────────────────────────────┐
│ 1. CARD READ (no charge) │
│ Terminal reads the card and returns │
│ a token/member identifier │
│ • Nets: SendJson → member ID from Storebox │
│ • Verifone: Card Acquisition → card token │
└──────────────────┬──────────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ 2. DILLER LOOKUP │
│ POS sends the identifier to Diller API │
│ → Returns member details + available coupons│
└──────────────────┬──────────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ 3. APPLY BENEFITS │
│ POS applies coupons/discounts to the basket │
│ and calculates the final amount │
│ Example: 349 NOK → 299 NOK after discount │
└──────────────────┬──────────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ 4. PAYMENT (card charged) │
│ Terminal processes a normal TransferAmount │
│ (or equivalent) for the discounted total │
│ Customer taps/inserts card │
└─────────────────────────────────────────────────┘
```
The member must have **pre-registered their card** in Diller . If the card is not recognized, the POS can fall back to phone number lookup and then register the card for future Tap2ID use.
---
## Tap2ID with Nets (Baxi.NET)
### Baxi Prerequisites
- **BAXI.NET SDK** (`baxi_dotnet.dll` v1.14.1 or later) — available from NexiGroup
- Terminal with **Storebox/DAM** support enabled (contact Nets/NexiGroup)
- `PreventLoyaltyFromPurchase` property set to `0` on the BaxiCtrl instance
- `UseExtendedLocalMode` property set to `1`
- Diller API credentials (`client_id`, `client_secret`, `store_id`)
### Baxi Step 1: Read Card & Identify Member
At the start of checkout, send a **SendJson** call to the terminal with a `GetAsset` (action 193) request. This prompts the customer to tap their card. The terminal reads the card and queries Storebox for a linked member ID — **without charging the card**.
**SendJson Request:**
```json
{
"da": {
"ver": "1.0",
"type": 101,
"action": 193,
"ra2t": {
"ver": "1.0",
"query": [
{
"mode": 4,
"amount": "34900",
"txntype": "30"
}
]
},
"ra2dam": {
"ver": "2.0",
"requestid": "20260213143022-a1b2",
"getasset": {
"asset": {
"template": {
"name": "storebox"
},
"keys": [
{ "cardref": "<cardref.001>" }
]
}
}
}
}
}
```
| Field | Description |
|-------|-------------|
| `type: 101` | Asset query message type |
| `action: 193` | GetAsset — read card and fetch linked data |
| `mode: 4` | Transaction + asset lookup mode |
| `amount` | The basket total in **øre** (cents). 349.00 NOK = `"34900"` |
| `txntype: "30"` | Indicates a purchase context |
| `requestid` | A unique request identifier you generate (e.g., timestamp + random) |
| `template.name: "storebox"` | Target the Storebox DAM system |
| `cardref: "<cardref.001>"` | Literal placeholder — the terminal replaces this with the actual card reference after tap |
> **Important**: The `<cardref.001>` value must be sent as a literal string including the angle brackets. Ensure your JSON serializer does not escape the `<` and `>` characters.
**Calling SendJson in code:**
```csharp
var args = new SendJsonEventArgs
{
JsonString = jsonPayload // The JSON above as a string
};
_baxi.SendJson(args);
```
**Response — OnLocalMode / OnJsonReceived event:**
The terminal fires `OnLocalMode` (or `OnJsonReceived`) when the customer taps their card. The response contains the DAM data:
```json
{
"da": {
"ver": "1.0",
"type": 101,
"action": 193,
"status": "5:0",
"statustext": "OK",
"dam2ra": {
"requestid": "20260213143022-a1b2",
"responseid": "6b9e963e-eec2-4615-a20f-f47d60185c8e",
"ver": "2.0",
"getasset": {
"asset": {
"template": "92debb63-0cc5-4570-aeaf-a3f9fb6c0563",
"keys": [
{ "cardref": "57fb361c-75b6-11eb-a45e-5c4242535400" }
],
"attributes": [
{
"payload": "{\"id\":\"800unxobgy...\",\"posapi\":{\"userId\":[{\"type\":\"pan\",\"value\":\"57fb361c-75b6-11eb-a45e-5c4242535400\"}]},\"cardlinkapi\":{...}}"
}
]
}
}
}
}
}
```
**Extracting the member identifier:**
Navigate the response JSON:
1. `da.dam2ra.getasset.asset.keys[0].cardref` → the card reference UUID (e.g., `"57fb361c-75b6-11eb-a45e-5c4242535400"`)
2. `da.dam2ra.getasset.asset.attributes[0].payload` → a JSON string. Parse it to extract:
- `memberId` or `loyaltyapi.memberId` — the Diller member ID
- `posapi.userId[0].value` — the card reference (same as above)
Use the **member ID** to query the Diller API in the next step.
### Baxi Step 2: Query Diller for Member Details
Once you have the member identifier from Storebox, query the Diller API to get the full member profile and available coupons:
```
GET https://api.dillerapp.com/api/v2.0/stores/{storeId}/members/search?cardidentifier={memberId}
Authorization: Bearer {access_token}
```
If the member is found, fetch their coupons:
```
GET https://api.dillerapp.com/api/v2.0/stores/{storeId}/members/{memberId}/coupons/
Authorization: Bearer {access_token}
```
Display the available coupons/discounts to the cashier and let them select which ones to apply. Recalculate the basket total with the discounts.
See [Diller API Reference](#diller-api-reference) below for full endpoint details.
### Baxi Step 3: Process Payment
After applying discounts and calculating the final amount, perform a standard **TransferAmount** call to charge the card:
```csharp
var args = new TransferAmountEventArgs
{
OperID = "0000",
Type1 = 0x30, // Purchase
Amount1 = 29900, // 299 NOK (in øre) — the discounted total
Type2 = 0x30,
Amount2 = 0,
Type3 = 0x30,
Amount3 = 0,
HostData = "",
ArticleDetails = "",
PaymentConditionCode = "",
AuthCode = ""
};
_baxi.TransferAmount(args);
// Wait for OnLocalMode event — customer taps/inserts card and enters PIN
```
| Field | Description |
|-------|-------------|
| `Type1 = 0x30` | Purchase transaction |
| `Type1 = 0x31` | Refund transaction |
| `Amount1` | Amount in **øre** (cents). 299.00 NOK = `29900` |
The `OnLocalMode` event fires when the transaction completes, providing the result (`args.Result`), truncated PAN, auth code, timestamp, and terminal ID.
After successful payment, sync the transaction to Diller (see [Create Transaction](#create-transaction)).
### Baxi Registering a New Card
If the Storebox lookup returns no member data (card not registered), you can:
1. Ask the customer for their phone number
2. Search Diller by phone: `GET /api/v2.0/stores/{storeId}/members/search?phone={phone}`
3. If found, link the card to the member using **InsertAsset** (action 191):
**InsertAsset Request:**
```json
{
"da": {
"ver": "1.0",
"type": 101,
"action": 191,
"ra2t": {
"ver": "1.0",
"query": [
{ "mode": 4 }
]
},
"ra2dam": {
"ver": "2.0",
"requestid": "20260213144500-c3d4",
"insertasset": {
"asset": {
"template": {
"name": "storebox"
},
"keys": [
{ "cardref": "<cardref.001>" }
],
"attributes": [
{ "msisdn": "4712345678" },
{ "memberno": "m_abc123def" }
]
}
}
}
}
}
```
| Field | Description |
|-------|-------------|
| `action: 191` | InsertAsset — associate card with member |
| `msisdn` | Member's phone number with country code (e.g., `"4712345678"` for Norway) |
| `memberno` | Diller member ID (from the phone search result) |
| `cardref: "<cardref.001>"` | Terminal replaces with the tapped card's reference |
The terminal prompts the customer to tap their card. On success, the card → member link is stored in Storebox, and future taps will return the member ID automatically.
**Success response:**
```json
{
"da": {
"ver": "1.0",
"type": 101,
"action": 191,
"status": "5:0",
"statustext": "OK",
"dam2ra": {
"requestid": "20260213144500-c3d4",
"responseid": "...",
"ver": "2.0",
"insertasset": {
"asset": {
"keys": [{ "cardref": "f37388e0-0a1f-11eb-b596-5c4242535400" }],
"attributes": [{ "payload": "..." }]
}
}
}
}
}
```
Check `statustext === "OK"` to confirm the card was registered successfully.
---
## Tap2ID with Verifone
### Verifone Prerequisites
- **Verifone PaymentSdk** (PSDK v3.68.7 or later) — `PaymentSdk-x64-net5.0.dll`
- Verifone P630 terminal (or compatible model)
- **Tokenization** enabled on the Verifone backend for your terminal TID (contact Verifone support)
- Terminal connection via TCP/IP or serial
- Diller API credentials (`client_id`, `client_secret`, `store_id`)
The Verifone integration uses a different approach than Nets. Instead of the DAM/Storebox system, it uses the PaymentSdk's **Card Acquisition** feature to read the card and generate a cryptographic token, which is then used as the Diller identifier.
### Verifone Step 1: Card Acquisition
The SDK must be initialized and a session must be active before performing a card acquisition. The initialization sequence is:
```
1. Initialize SDK → PaymentSdk.InitializeFromValues(listener, params)
2. Login → TransactionManager.LoginWithCredentials(credentials)
3. Start Session → TransactionManager.StartSession(transaction)
4. Card Acquisition → TransactionManager.RequestCardData2(request)
```
**Card Acquisition call:**
```csharp
var request = CardAcquisitionRequest.Create(
tokenRequest: true, // IMPORTANT: Request tokenization
message: "Please tap card", // Terminal display message
presentationMethods: new[] {
CardPresentationMethod.CTLS_CARD, // Contactless
CardPresentationMethod.CHIP, // Chip insert
CardPresentationMethod.MAG_STRIPE // Swipe (fallback)
}
);
_transactionManager.RequestCardData2(request);
// Wait for CardInformationReceivedEvent callback (up to 60 seconds)
```
> **Important**: `tokenRequest: true` is essential — it tells the Verifone system to generate tokens for the card. Without this, you will not get the identifier needed for Diller. Tokenization must also be enabled on the backend/terminal configuration through Verifone support.
**Response — CardInformationReceivedEvent:**
When the customer taps their card, the SDK fires the `HandleCardInformationReceivedEvent` callback. Extract the card data:
```csharp
// In your CommerceListener2 implementation:
public override void HandleCardInformationReceivedEvent(CardInformationReceivedEvent evt)
{
var cardInfo = evt.CardInformation;
// Card details
string brand = cardInfo.PaymentBrand; // "VISA", "MASTERCARD", etc.
string panLast4 = cardInfo.PanLast4; // "1234"
string expiry = cardInfo.CardExpiry; // "2612" (YYMM)
// Tokens — this is what you send to Diller
var tokens = cardInfo.Tokens; // Array of token objects
foreach (var token in tokens)
{
string type = token.TokenType; // "ANALYTICS", "REUSE", etc.
string value = token.Value; // The token string
string scheme = token.Scheme; // "VISA", etc.
}
// PanHandle — alternative identifier
string panHandle = cardInfo.PanHandle;
}
```
**Token types you may receive:**
| Token Type | Description | Use for Diller? |
|------------|-------------|-----------------|
| `ANALYTICS` | Persistent card identifier generated by Verifone backend | **Yes — preferred** |
| `REUSE` | Token for reusing the card in subsequent transactions | Fallback if ANALYTICS not available |
**Use the `ANALYTICS` token** (or `REUSE` as fallback) as the card identifier for Diller member lookup.
### Verifone Step 2: Query Diller for Member Details
With the token from card acquisition, query the Diller API:
```
GET https://api.dillerapp.com/api/v2.0/stores/{storeId}/members/search?cardidentifier={analyticsToken}
Authorization: Bearer {access_token}
```
If the member is found, fetch their coupons:
```
GET https://api.dillerapp.com/api/v2.0/stores/{storeId}/members/{memberId}/coupons/
Authorization: Bearer {access_token}
```
Display coupons to the cashier, apply discounts, and calculate the final amount.
See [Diller API Reference](#diller-api-reference) below for full details.
### Verifone Step 3: Process Payment
After discounts are applied, process payment using the standard PaymentSdk flow:
```csharp
var payment = Payment.Create();
// Amount in minor units (øre/cents)
var amount = VerifoneSdk.Decimal.Create(29900); // 299.00 NOK
payment.AmountTotals.Subtotal = amount;
payment.AmountTotals.Total = amount;
payment.Currency = "578"; // ISO 4217 numeric (578=NOK, 752=SEK, 978=EUR)
payment.TransactionType = TransactionType.PAYMENT;
payment.Invoice = "INV-2026-001";
// Card presentation methods (customer will tap/insert again)
payment.RequestedCardPresentationMethods = new[] {
CardPresentationMethod.CTLS_CARD,
CardPresentationMethod.CHIP,
CardPresentationMethod.MAG_STRIPE
};
_transactionManager.StartPayment(payment);
// Wait for PaymentCompletedEvent callback (up to 90 seconds for PIN entry)
```
**PaymentCompletedEvent:**
```csharp
public override void HandlePaymentCompletedEvent(PaymentCompletedEvent evt)
{
var result = evt.Payment.AuthorizationResult; // AUTHORIZED, DECLINED, etc.
var txnId = evt.Payment.TransactionId;
var auth = evt.Payment.AuthCode;
if (result == AuthorizationResult.AUTHORIZED)
{
// Payment successful
}
}
```
| Currency | ISO 4217 Numeric |
|----------|-----------------|
| NOK | `"578"` |
| SEK | `"752"` |
| EUR | `"978"` |
| DKK | `"208"` |
| GBP | `"826"` |
After successful payment, sync the transaction to Diller (see [Create Transaction](#create-transaction)).
### Verifone Registering a New Card
If the Diller API returns no member for the token (card not registered), you can:
1. Ask the customer for their phone number
2. Search Diller by phone: `GET /api/v2.0/stores/{storeId}/members/search?phone={phone}`
3. If a member is found, register the card token to that member:
```
POST https://api.dillerapp.com/api/v2.0/stores/{storeId}/members/{memberId}/register-card
Authorization: Bearer {access_token}
Content-Type: application/json
{
"identifier": "tok_analytics_xxxx...",
"brand": "VISA",
"expiry_date": "26-12"
}
```
| Field | Description |
|-------|-------------|
| `identifier` | The `ANALYTICS` token value from card acquisition |
| `brand` | Normalized card brand: `"VISA"`, `"MASTERCARD"`, `"AMERICAN EXPRESS"`, etc. |
| `expiry_date` | Expiry in `"YY-MM"` format (e.g., `"26-12"` for December 2026) |
After registration, future Tap2ID lookups with this token will return the member instantly.
> **Note**: The brand should be uppercase. Common mappings: `MC` → `MASTERCARD`, `AMEX` → `AMERICAN EXPRESS`.
> **Note**: Terminal expiry formats vary. You may receive `YYMM` (e.g., `2612`), `MMYY` (e.g., `1226`), or `YY/MM`. Normalize to `YY-MM` before sending to Diller.
---
## Diller API Reference
### Authentication
Diller uses **OAuth2 Client Credentials** flow. Obtain an access token before making API calls:
```
POST https://api.dillerapp.com/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=api.retailer&client_id={your_client_id}&client_secret={your_client_secret}
```
**Response:**
```json
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "api.retailer"
}
```
Cache the token and refresh when expired. Use it in all subsequent requests:
```
Authorization: Bearer {access_token}
```
| Environment | Base URL |
|-------------|----------|
| Production | `https://api.dillerapp.com` |
| Pre-release / Testing | `https://api.prerelease.dillerapp.com` |
---
### Identify Member by Card Token
Look up a member using the card token/identifier obtained from the terminal.
```
GET /api/v2.0/stores/{storeId}/members/search?cardidentifier={token}
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `storeId` | path | Your Diller store ID |
| `cardidentifier` | query | The token from card acquisition (Verifone ANALYTICS token or Nets Storebox member ID) |
**Response (member found):**
```json
[
{
"id": "m_nsr714RRBEHX",
"first_name": "Ola",
"last_name": "Nordmann",
"phone": { "country_code": "+47", "number": "12345678" },
"email": "ola@example.com",
"stamps": { "current": 5, "needed": 10 },
"points": { "current": 250 },
"membership_level": "Gold",
...
}
]
```
**Response (no member found):**
```json
[]
```
If the response is empty, the card is not registered. Proceed to phone number search or enrollment.
---
### Search Member by Phone
```
GET /api/v2.0/stores/{storeId}/members/search?phone={phoneNumber}
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `phone` | query | Phone number (e.g., `"12345678"` or `"+4712345678"`) |
Returns the same member object structure as above.
---
### Get Member Coupons
After identifying a member, fetch their available coupons:
```
GET /api/v2.0/stores/{storeId}/members/{memberId}/coupons/
```
**Response:**
```json
[
{
"id": "coupon_abc123",
"name": "20% off everything",
"type": "percentage",
"value": 20,
"min_purchase_amount": 100,
"expires_at": "2026-03-01T00:00:00Z",
"is_redeemable": true,
...
}
]
```
Apply eligible coupons to the basket, recalculate the total, and use the discounted amount for the payment step.
---
### Register Card to Member
Register a card token so the member can be identified by Tap2ID in the future. Used for Verifone (and other token-based terminals). For Nets/Baxi, use the terminal's InsertAsset (action 191) instead.
```
POST /api/v2.0/stores/{storeId}/members/{memberId}/register-card
Content-Type: application/json
Authorization: Bearer {access_token}
{
"identifier": "tok_analytics_xxxx...",
"brand": "VISA",
"expiry_date": "26-12"
}
```
| Field | Type | Description |
|-------|------|-------------|
| `identifier` | string | Card token (ANALYTICS token from Verifone) |
| `brand` | string | Card brand, uppercase: `VISA`, `MASTERCARD`, `AMERICAN EXPRESS` |
| `expiry_date` | string | Card expiry in `YY-MM` format |
**Returns:** 200 OK on success.
---
### Enroll New Member
If no member exists for the phone number, enroll a new one:
```
POST /api/v2.0/stores/{storeId}/members/enroll
Content-Type: application/json
Authorization: Bearer {access_token}
{
"phone": {
"country_code": "+47",
"number": "12345678"
},
"department_id": "101",
"consent": true,
"origin": {
"system_id": "your-pos-system",
"employee_id": "1",
"department_id": "101",
"channel": "pos"
},
"additional_info": {
"first_name": "Ola",
"last_name": "Nordmann",
"email": "ola@example.com"
}
}
```
**Returns:** 201 Created with the new member object (includes `id`).
After enrollment, register the customer's card using either the Diller API (Verifone) or InsertAsset (Nets) for future Tap2ID recognition.
---
### Create Transaction
After a successful payment with a loyalty member, sync the transaction to Diller so points/stamps are awarded:
```
POST /api/v2.0/stores/{storeId}/members/{memberId}/transactions
Content-Type: application/json
Authorization: Bearer {access_token}
{
"external_id": "ORDER-12345",
"total": 299.00,
"currency": "NOK",
"created_at": "2026-02-13T14:30:00Z",
"origin": {
"system_id": "your-pos-system",
"employee_id": "1",
"department_id": "101",
"channel": "pos"
},
"details": [
{
"product_id": "SKU-001",
"product_name": "Example Product",
"quantity": 1,
"unit_price": 349.00,
"total": 349.00
}
],
"coupons": [
{
"coupon_id": "coupon_abc123",
"discount_amount": 50.00
}
]
}
```
---
## Key Differences
| Aspect | Nets (Baxi) | Verifone |
|--------|-------------|----------|
| **SDK** | BAXI.NET (`baxi_dotnet.dll`) — COM control | PaymentSdk (PSDK) — .NET library |
| **Card Read** | `SendJson` with DAM GetAsset (action 193) | `RequestCardData2` with `tokenRequest: true` |
| **Identifier Type** | Storebox member ID (embedded on card via DAM) | ANALYTICS token (cryptographic, server-generated) |
| **Diller Lookup** | `?cardidentifier={storebixMemberId}` | `?cardidentifier={analyticsToken}` |
| **Card Registration** | Terminal-side: InsertAsset (action 191) writes to Storebox | API-side: `POST /members/{id}/register-card` writes to Diller |
| **Initialization** | `BaxiCtrl.Open()` → ready | Initialize → Login → Start Session → ready |
| **Session Management** | Not required (stateless) | Required (explicit session start/end) |
| **Amount Format** | String in øre for SendJson, integer in øre for TransferAmount | Integer in minor units (øre/cents) |
| **Currency** | Configured on terminal | Passed per-request as ISO 4217 numeric code |
| **OS Requirement** | Windows only (COM/WinForms) | Windows or Linux |
| **Threading** | STA thread required (COM) | Standard async |
| **Payment Call** | `TransferAmount` (type `0x30`) | `StartPayment` with `TransactionType.PAYMENT` |
| **Refund Call** | `TransferAmount` (type `0x31`) | `StartPayment` with `TransactionType.REFUND` |
---
## Complete Flow Diagrams
### Nets (Baxi) — Card Recognized
```
POS Terminal Storebox Diller API
│ │ │ │
│ SendJson(GetAsset 193) │ │ │
│───────────────────────►│ │ │
│ │ Customer taps card │ │
│ │─────────────────────► │
│ │ memberId │ │
│ { memberId, │◄───────────────────── │
│ cardRef } │ │ │
│◄───────────────────────│ │ │
│ │ │ │
│ GET /members/search?cardidentifier={memberId} │
│────────────────────────────────────────────────────────────────►│
│ { member data } │
│◄────────────────────────────────────────────────────────────────│
│ │ │ │
│ GET /members/{id}/coupons │
│────────────────────────────────────────────────────────────────►│
│ { coupons[] } │
│◄────────────────────────────────────────────────────────────────│
│ │ │ │
│ ── Apply discounts, recalculate total ── │ │
│ │ │ │
│ TransferAmount(0x30, │ │ │
│ 29900 øre) │ │ │
│───────────────────────►│ │ │
│ │ Customer taps + PIN │ │
│ { success, authCode } │ │ │
│◄───────────────────────│ │ │
│ │ │ │
│ POST /members/{id}/transactions │
│────────────────────────────────────────────────────────────────►│
```
### Verifone — Card Recognized
```
POS Terminal Verifone Cloud Diller API
│ │ │ │
│ Initialize + Login │ │ │
│───────────────────────►│ │ │
│ Start Session │ │ │
│───────────────────────►│ │ │
│ │ │ │
│ RequestCardData2 │ │ │
│ (tokenRequest=true) │ │ │
│───────────────────────►│ │ │
│ │ Customer taps card │ │
│ │ ────────────────────► │
│ │ ANALYTICS token │ │
│ CardInformation │◄───────────────────── │
│ { token, brand, │ │ │
│ last4, expiry } │ │ │
│◄───────────────────────│ │ │
│ │ │ │
│ GET /members/search?cardidentifier={analyticsToken} │
│────────────────────────────────────────────────────────────────►│
│ { member data } │
│◄────────────────────────────────────────────────────────────────│
│ │ │ │
│ GET /members/{id}/coupons │
│────────────────────────────────────────────────────────────────►│
│ { coupons[] } │
│◄────────────────────────────────────────────────────────────────│
│ │ │ │
│ ── Apply discounts, recalculate total ── │ │
│ │ │ │
│ StartPayment │ │ │
│ (29900 øre, NOK) │ │ │
│───────────────────────►│ │ │
│ │ Customer taps + PIN │ │
│ PaymentCompleted │ │ │
│ { txnId, authCode } │ │ │
│◄───────────────────────│ │ │
│ │ │ │
│ End Session │ │ │
│───────────────────────►│ │ │
│ │ │ │
│ POST /members/{id}/transactions │
│────────────────────────────────────────────────────────────────►│
```
### Either Terminal — Card Not Recognized (First-Time Registration)
```
POS Terminal Diller API
│ │ │
│ Card read (no charge) │ │
│───────────────────────►│ │
│ { token/cardRef } │ │
│◄───────────────────────│ │
│ │ │
│ GET /members/search?cardidentifier={token} │
│──────────────────────────────────────────────►│
│ [] (empty)│
│◄──────────────────────────────────────────────│
│ │ │
│ ── Cashier asks customer for phone ── │
│ │ │
│ GET /members/search?phone=12345678 │
│──────────────────────────────────────────────►│
│ { member found } │
│◄──────────────────────────────────────────────│
│ │ │
│ ── Register card for future Tap2ID ── │
│ │ │
│ NETS: InsertAsset(191)│ │
│───────────────────────►│ │
│ { OK } │ │
│◄───────────────────────│ │
│ │ │
│ VERIFONE: │
│ POST /members/{id}/register-card │
│ { identifier, brand, expiry_date } │
│──────────────────────────────────────────────►│
│ { OK } │
│◄──────────────────────────────────────────────│
│ │ │
│ ── Continue to coupons + payment ── │
```
---
## FAQ & Troubleshooting
### General
**Q: Does the first card read (Tap #1) charge the customer?**
A: No. Both the Nets SendJson/GetAsset and Verifone Card Acquisition are read-only operations that do not charge the card. The customer is only charged during the explicit payment step (TransferAmount or StartPayment).
**Q: What if the customer's card is not registered?**
A: The POS should fall back to phone number lookup. If a member is found by phone, register the card (InsertAsset for Nets, register-card API for Verifone) so that future visits use Tap2ID automatically.
**Q: Can I use the same Diller credentials for both terminal types?**
A: Yes. Diller credentials (`client_id`, `client_secret`, `store_id`) are terminal-independent. The only difference is how you obtain the card identifier.
### Nets (Baxi) Specific
**Q: SendJson returns no member data / empty attributes**
A: Storebox/DAM must be configured on the terminal. Contact NexiGroup to enable Storebox with the `"storebox"` template for your terminal fleet.
**Q: `MethodRejectCode: 7001` (invalid JSON)**
A: Ensure the `<cardref.001>` angle brackets are not escaped. Use a JSON serializer that preserves literal `<` and `>` characters.
**Q: `MethodRejectCode: 7002` (not ready)**
A: The terminal is not in a ready state. Wait for the `OnTerminalReady` event before sending commands. You may need to reinitialize.
**Q: InsertAsset fails with phone number error**
A: Ensure the phone number includes the country code prefix (e.g., `"4712345678"` for Norwegian numbers, not just `"12345678"`).
### Verifone Specific
**Q: Card acquisition returns no tokens**
A: Tokenization must be enabled on the Verifone backend for your terminal TID. Contact your Verifone account manager to enable the ANALYTICS token type for card acquisition.
**Q: "Terminal not initialized" error**
A: The SDK requires the full initialization sequence: Initialize → Login → Start Session. If the terminal was powered off or the connection dropped, you need to re-initialize.
**Q: Currency mismatch / wrong amount charged**
A: Ensure the currency code is ISO 4217 numeric (e.g., `"578"` for NOK, not `"NOK"`). Amounts must be in minor units (øre/cents).
**Q: Session already open error**
A: End the current session before starting a new one. The SDK only allows one active session at a time.
### Diller API
**Q: 401 Unauthorized from Diller API**
A: Your access token has expired. Re-authenticate using the `/connect/token` endpoint. Tokens typically expire after 1 hour.
**Q: Card registration returns an error**
A: Verify the brand is uppercase (`"VISA"`, not `"visa"`) and the expiry format is `"YY-MM"` (e.g., `"26-12"`, not `"2612"` or `"12/26"`).
---
*For questions about Diller API access or terminal provisioning, contact [support@diller.io](mailto:support@diller.io).*
|Was this article helpful?
Sorry about that! Care to tell us more?
