Card POS
Description
Card-Present (POS) payments allow merchants to accept card payments through physical payment terminals at brick-and-mortar locations. These transactions require additional security information captured during the card-terminal interaction, including EMV chip data, Track2 data from magnetic stripes, and optional encrypted PIN blocks for online PIN verification. POS payments support traditional POS devices and software-only terminals (SoftPOS).
Availability
Mastercard and Visa is accepted in over 200 countries and territories worldwide.
Transaction Types
The following transaction types are currently available:
- Payment
- Refund (Full and partial refund, referenced)
- Payout (To be used for unreferenced refunds. E.g direct transfers to a given card)
- Authorization with manual clearing
- Capture (Full and partial capture)
- Reversals (Full and partial reversals)
Integration Types
The following integration type is currently available:
Payment Flow
API Implementation
Required value for payment_type parameter: cardpos
Server-to-Server Processing
Send card-present transaction data directly from your POS terminal integration. The terminal must capture and provide the necessary card data, EMV data, and terminal information.
Implementation flow:
- Payer presents card at POS terminal.
- Terminal reads card data (chip, contactless, or magnetic stripe).
- Make a Payment API request with card-present specific parameters.
- Handle terminal actions if required (e.g., PIN request, interface switch).
- Receive API response with transaction result.
Payment API Request
Common Parameters
api_keyStringrequiredpayment_typeStringrequiredcardposorder_idStringrequiredamountFloatrequiredcurrencyStringrequiredpostback_urlStringrequiredPOST /rest/payment
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"api_key": "70abd594084787a392e8",
"payment_type": "cardpos",
"order_id": "POS-12345678",
"amount": "25.50",
"currency": "EUR",
"postback_url": "https://your-postback.url.com"
}
POS Data — Transaction Type
terminal_entry_modeStringrequiredchip, contactless, magstripe, magstripe-fallback, or manual-entry{
"pos_data": {
"type": {
"terminal_entry_mode": "contactless"
}
}
}
POS Data — Card
numberStringrequiredexpiry_monthIntegerrequiredexpiry_yearIntegerrequiredtrack2_dataStringterminal_entry_mode is chip, contactless, magstripe, or magstripe-fallback.emv_dataStringcard_sequence_numberString{
"pos_data": {
"card": {
"number": "4761739001010010",
"expiry_month": 12,
"expiry_year": 2027,
"track2_data": "4761739001010010D27121200000000000F",
"emv_data": "9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000"
}
}
}
POS Data — Terminal
idStringrequired87654321, AAFF). Issued during terminal onboarding.typeStringrequiredpos or softpos.attendedBooleanrequiredtrue for attended terminals, false for unattended. For softpos, must be true.capabilitiesArray of Stringrequiredterminal.type; see Terminal Capabilities below.{
"pos_data": {
"terminal": {
"id": "87654321",
"type": "softpos",
"attended": true,
"capabilities": ["contactlessChip", "onlinePin", "noCvm"]
}
}
}
Terminal Capabilities
The capabilities array lists every entry / verification mode the terminal is capable of. Multiple values are allowed and indicate the terminal can perform all of those things.
For type: "pos" — one or more of:
| Value | Description |
|---|---|
contactChip | Reads EMV chip via insertion |
contactlessChip | Reads EMV chip via NFC tap |
contactMagStripe | Reads magnetic stripe via swipe |
contactlessMagStripe | Reads magnetic stripe via NFC (legacy MSD) |
offlineEncipheredPin | Verifies PIN offline using encrypted PIN block |
offlinePlaintextPin | Verifies PIN offline using plaintext PIN (legacy) |
onlinePin | Captures online PIN, sent to the issuer for verification |
signature | Captures cardholder signature |
keyEntry | Accepts manual PAN entry |
noCvm | No cardholder verification (e.g. low-value contactless) |
oneTap | Supports Single Tap (combined PIN entry + transaction) |
If capabilities includes keyEntry or signature, then attended must be true.
For type: "softpos" — one or more of:
| Value | Description |
|---|---|
contactlessChip | Reads EMV chip via NFC tap |
onlinePin | Captures online PIN, sent to the issuer for verification |
signature | Captures cardholder signature |
noCvm | No cardholder verification |
oneTap | Supports Single Tap |
Payment API Response (Success)
transaction_idStringpayment_typeStringstatus_codeIntegerstatusStringorder_idStringmessageStringincluded_feesStringerror_codeInteger{
"transaction_id": "938834bc-769f-44e7-ab25-da9aeaad5346",
"payment_type": "cardpos",
"status_code": 3,
"status": "completed",
"order_id": "POS-12345678",
"message": null,
"included_fees": "0.00",
"error_code": 0
}
Payment API Response (PIN Required — Single Tap)
transaction_idStringpayment_typeStringstatus_codeIntegerstatusStringorder_idStringerror_codeIntegeraction_dataObjectterminal_action indicating the required terminal-side action{
"transaction_id": "938834bc-769f-44e7-ab25-da9aeaad5346",
"payment_type": "cardpos",
"status_code": 1,
"status": "started",
"order_id": "POS-12345678",
"error_code": 0,
"action_data": {
"terminal_action": "request_pin"
}
}
Retry Request with PIN Block
Common Parameters
api_keyStringrequiredpayment_typeStringrequiredcardposorder_idStringrequiredamountFloatrequiredcurrencyStringrequiredpostback_urlStringrequiredPOST /rest/payment
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"api_key": "70abd594084787a392e8",
"payment_type": "cardpos",
"order_id": "POS-12345678",
"amount": "25.50",
"currency": "EUR",
"postback_url": "https://your-postback.url.com"
}
POS Data — Transaction Type (Retry)
terminal_entry_modeStringrequiredchip, contactless, magstripe, magstripe-fallback, or manual-entrysequenceStringrequiredsubsequent for retry after a terminal action{
"pos_data": {
"type": {
"terminal_entry_mode": "contactless",
"sequence": "subsequent"
}
}
}
POS Data — Card (Retry)
numberStringrequiredexpiry_monthIntegerrequiredexpiry_yearIntegerrequiredtrack2_dataStringterminal_entry_mode is chip, contactless, magstripe, or magstripe-fallback.emv_dataStringcard_sequence_numberString{
"pos_data": {
"card": {
"number": "4761739001010010",
"expiry_month": 12,
"expiry_year": 2027,
"track2_data": "4761739001010010D27121200000000000F",
"emv_data": "9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000"
}
}
}
POS Data — PIN Block
Required only when online PIN verification is needed (e.g., high-value contactless transactions). When supplied, all four sub-fields are required.
formatStringrequiredISO-0, ISO-1, ISO-4.blockStringrequiredISO-0/ISO-1; 32 hex chars for ISO-4.zone_idStringrequiredkey_idStringrequired{
"pos_data": {
"pin_block": {
"format": "ISO-0",
"block": "D766AAA13ED5CA50",
"zone_id": "pos-gateway",
"key_id": "0001"
}
}
}
POS Data — Terminal (Retry)
idStringrequiredtypeStringrequiredpos or softpos.attendedBooleanrequiredtrue for attended terminals, false for unattended. For softpos, must be true.capabilitiesArray of Stringrequired{
"pos_data": {
"terminal": {
"id": "87654321",
"type": "softpos",
"attended": true,
"capabilities": ["contactlessChip", "onlinePin", "noCvm"]
}
}
}
Authorization for Manual Clearing
To authorize a payment without immediate capture (useful for reservations or when final amount may change):
Authorization API Request
POST /rest/authorize
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"api_key": "70abd594084787a392e8",
"payment_type": "cardpos",
"order_id": "POS-12345678",
"amount": "25.50",
"currency": "EUR",
"postback_url": "https://your-postback.url.com",
"pos_data": {
"type": { "terminal_entry_mode": "contactless" },
"card": {
"number": "4761739001010010",
"expiry_month": 12,
"expiry_year": 2027,
"track2_data": "4761739001010010D27121200000000000F",
"emv_data": "9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000"
},
"terminal": {
"id": "87654321",
"type": "softpos",
"attended": true,
"capabilities": ["contactlessChip", "onlinePin", "noCvm"]
}
}
}
Capture Authorized Payments
To capture a previously authorized POS payment (full or partial amount):
Capture API Request
transaction_idStringrequiredapi_keyStringrequiredamountFloatrequiredPOST /rest/capture
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"transaction_id": "e06dec72-788e-471a-a33f-a9d0deeeb4df",
"api_key": "70abd594084787a392e8",
"amount": 25.50
}
Capture API Response
transaction_idStringstatus_codeIntegerstatusStringorder_idStringmessageStringcard_last_fourStringcard_brandStringerror_codeInteger{
"transaction_id": "e06dec72-788e-471a-a33f-a9d0deeeb4df",
"status_code": 3,
"status": "completed",
"order_id": "POS-12345678",
"message": null,
"card_last_four": "0010",
"card_brand": "VISA",
"error_code": 0
}
Payout (Unreferenced Refunds)
To send money directly to a card without a prior payment transaction:
Payout API Request
api_keyStringrequiredpayment_typeStringrequiredcardposorder_idStringrequiredamountFloatrequiredcurrencyStringrequiredmerchant_referenceStringpostback_urlStringrequiredPOST /rest/payout
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"api_key": "70abd594084787a392e8",
"payment_type": "cardpos",
"order_id": "PAYOUT-12345678",
"amount": "50.00",
"currency": "EUR",
"merchant_reference": "Refund for order XYZ",
"postback_url": "https://your-postback.url.com"
}
POS Data — The pos_data object for payouts uses the same structure as the Payment API. See the POS Data sections above for pos_data.type, pos_data.card, and pos_data.terminal parameters.
Payout API Response
transaction_idStringstatus_codeIntegerstatusStringorder_idStringerror_codeInteger{
"transaction_id": "0b3c2327-9394-4ab4-be18-6e9d85e652fd",
"status_code": 2,
"status": "pending",
"order_id": "PAYOUT-12345678",
"error_code": 0
}
Advanced Features
Partial Approval
To support partial approval (common with prepaid cards):
{
"pos_data": {
"allow_partial_approval": true
}
}
Cash Back
For Visa and Mastercard, cashback is expressed as a sub-amount of the total charge amount. Send the cashback portion in minor units (cents) inside amount.breakdown.cashback:
{
"amount": "30.00",
"currency": "EUR",
"amount_breakdown": {
"cashback": 1000
}
}
The full amount must include the cashback sub-amount; type.intent must be purchase; emv_data must include valid data for EMV tag 9F03; and allow_partial_approval cannot be requested at the same time.
Gratuity (Tip)
Use manual clearing to add gratuity after the cardholder has tapped:
{
"pos_data": {
"type": {
"clearing_mode": "manual"
}
}
}
Authorize with clearing_mode: "manual" and the goods/services amount, then call the Capture endpoint with the final amount including gratuity.
Terminal Actions
When the issuer requests an additional cardholder verification step, the synchronous Payment API response carries an action_data.terminal_action field. The transaction stays in started status — you must retry the call to complete it.
request_pin
Returned when online PIN verification is required (typical for Mastercard Single Tap above the cardholder verification limit). The terminal should:
- Prompt the cardholder for PIN.
- Encrypt the PIN with the terminal's encryption keys.
- Retry the transaction including
pos_data.pin_blockandpos_data.type.sequence: "subsequent".
switch_interface
Returned when the issuer requires switching from contactless to chip. The terminal should:
- Prompt the cardholder to insert the card.
- Read the card via the chip interface.
- Submit a new transaction with
pos_data.type.terminal_entry_mode: "chip".
EMV Response Data
For chip transactions the synchronous response may include action_data.new_emv_data — issuer-supplied EMV scripts that must be passed back to the integrated circuit card (ICC) without modification, before completing the cardholder receipt.
Postbacks
transaction_idStringpayment_typeStringstatus_codeStringstatusStringorder_idStringmessageStringadditional_transaction_dataStringpostback_url as part of the postback data.card_last_fourStringcard_expiry_yearStringcard_expiry_monthStringcard_brandStringcard_typeStringcard_countryStringincluded_feesStringexternal_transaction_idStringchecksumString{
"transaction_id": "938834bc-769f-44e7-ab25-da9aeaad5346",
"payment_type": "cardpos",
"status_code": "3",
"status": "completed",
"order_id": "POS-12345678",
"message": "",
"additional_transaction_data": "",
"card_last_four": "0010",
"card_expiry_year": "2027",
"card_expiry_month": "12",
"card_brand": "VISA",
"card_type": "DEBIT",
"card_country": "DE",
"included_fees": "0.00",
"external_transaction_id": "SF66TOoXap2bNLZ2m89tm1",
"checksum": "73a93b8a2d5260f592d98e386c4e5784ee551d1c"
}
For refund postbacks, see the Refund API. For retry policy and signature verification, see Postbacks.
Test Data
Contact your onboarding manager to receive:
- A sandbox merchant acceptor with a configured point-of-sale address
- A sandbox terminal id (alphanumeric, 1–8 characters)
- PIN encryption keys, zone, and key ids (only if you will test online-PIN flows)
- Access to the test environment
The values below match the ones used in the examples throughout this guide and are accepted by the test environment. You can paste them as-is once your sandbox merchant account and terminal are provisioned by Better Payment onboarding.
Sandbox Visa test card
| Field | Value |
|---|---|
card.number | 4761739001010010 |
card.expiry_month | 12 |
card.expiry_year | 2027 |
card.track2_data | 4761739001010010D27121200000000000F |
card.emv_data | 9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000 |
Sandbox SoftPOS terminal
| Field | Value |
|---|---|
terminal.id | 87654321 (replace with the id your onboarding manager provides for your tenant) |
terminal.type | softpos |
terminal.attended | true |
terminal.capabilities | ["contactlessChip", "onlinePin", "noCvm"] |
Note: POS charges do not accept card_cvv — the cardholder is authenticated by the terminal (PIN, signature, chip cryptogram) rather than by CVC.
POS payments require proper terminal hardware or certified software that can read card data and generate EMV transaction data. Ensure your terminal integration provides all required fields for successful processing.