Skip to main content

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:

  1. Payer presents card at POS terminal.
  2. Terminal reads card data (chip, contactless, or magnetic stripe).
  3. Make a Payment API request with card-present specific parameters.
  4. Handle terminal actions if required (e.g., PIN request, interface switch).
  5. Receive API response with transaction result.

Payment API Request

Common Parameters

api_keyStringrequired
Your API key
payment_typeStringrequired
cardpos
order_idStringrequired
Any alphanumeric string to identify the Merchant's order
amountFloatrequired
Amount of the transaction including all taxes and shipping fees
currencyStringrequired
3 letter currency code
postback_urlStringrequired
The URL for updates about transaction status are posted
This example includes only the minimum required parameters to create a Card POS payment via Server-to-Server. See the Create Payment API reference for the full list of supported parameters.
Example Request
POST /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_modeStringrequired
How the card was read: chip, contactless, magstripe, magstripe-fallback, or manual-entry
pos_data.type
{
"pos_data": {
"type": {
"terminal_entry_mode": "contactless"
}
}
}

POS Data — Card

numberStringrequired
Primary Account Number (PAN). For chip/contactless transactions, the PAN extracted from EMV / Track2 must still be sent here.
expiry_monthIntegerrequired
Card expiry month (1–12)
expiry_yearIntegerrequired
Card expiry year (4 digits)
track2_dataString
Track2 data from the card. Required when terminal_entry_mode is chip, contactless, magstripe, or magstripe-fallback.
emv_dataString
EMV data from the chip; submit unaltered as received from the terminal. Required for chip transactions.
card_sequence_numberString
Card sequence number if EMV tag 5F34 is personalized on the chip (1–3 digits).
pos_data.card
{
"pos_data": {
"card": {
"number": "4761739001010010",
"expiry_month": 12,
"expiry_year": 2027,
"track2_data": "4761739001010010D27121200000000000F",
"emv_data": "9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000"
}
}
}

POS Data — Terminal

idStringrequired
Terminal identifier, alphanumeric, 1–8 characters (e.g. 87654321, AAFF). Issued during terminal onboarding.
typeStringrequired
Terminal type: pos or softpos.
attendedBooleanrequired
true for attended terminals, false for unattended. For softpos, must be true.
capabilitiesArray of Stringrequired
Entry / verification modes the terminal supports. The allowed values depend on terminal.type; see Terminal Capabilities below.
pos_data.terminal
{
"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:

ValueDescription
contactChipReads EMV chip via insertion
contactlessChipReads EMV chip via NFC tap
contactMagStripeReads magnetic stripe via swipe
contactlessMagStripeReads magnetic stripe via NFC (legacy MSD)
offlineEncipheredPinVerifies PIN offline using encrypted PIN block
offlinePlaintextPinVerifies PIN offline using plaintext PIN (legacy)
onlinePinCaptures online PIN, sent to the issuer for verification
signatureCaptures cardholder signature
keyEntryAccepts manual PAN entry
noCvmNo cardholder verification (e.g. low-value contactless)
oneTapSupports Single Tap (combined PIN entry + transaction)
caution

If capabilities includes keyEntry or signature, then attended must be true.

For type: "softpos" — one or more of:

ValueDescription
contactlessChipReads EMV chip via NFC tap
onlinePinCaptures online PIN, sent to the issuer for verification
signatureCaptures cardholder signature
noCvmNo cardholder verification
oneTapSupports Single Tap

Payment API Response (Success)

transaction_idString
ID of the created transaction
payment_typeString
Payment type of the transaction
status_codeInteger
Status code of the transaction
statusString
Status of the transaction
order_idString
Order ID of the transaction
messageString
Optional additional information about the transaction result
included_feesString
Included fees for the transaction
error_codeInteger
Error code for the response
Example Response
{
"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_idString
ID of the created transaction
payment_typeString
Payment type of the transaction
status_codeInteger
Status code of the transaction
statusString
Status of the transaction
order_idString
Order ID of the transaction
error_codeInteger
Error code for the response
action_dataObject
Contains terminal_action indicating the required terminal-side action
Example Response
{
"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_keyStringrequired
Your API key
payment_typeStringrequired
cardpos
order_idStringrequired
Any alphanumeric string to identify the Merchant's order
amountFloatrequired
Amount of the transaction including all taxes and shipping fees
currencyStringrequired
3 letter currency code
postback_urlStringrequired
The URL for updates about transaction status are posted
Example Retry Request
POST /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_modeStringrequired
How the card was read: chip, contactless, magstripe, magstripe-fallback, or manual-entry
sequenceStringrequired
subsequent for retry after a terminal action
pos_data.type (retry)
{
"pos_data": {
"type": {
"terminal_entry_mode": "contactless",
"sequence": "subsequent"
}
}
}

POS Data — Card (Retry)

numberStringrequired
Primary Account Number (PAN).
expiry_monthIntegerrequired
Card expiry month (1–12)
expiry_yearIntegerrequired
Card expiry year (4 digits)
track2_dataString
Track2 data from the card. Required when terminal_entry_mode is chip, contactless, magstripe, or magstripe-fallback.
emv_dataString
EMV data from the chip; submit unaltered as received from the terminal. Required for chip transactions.
card_sequence_numberString
Card sequence number if EMV tag 5F34 is personalized on the chip (1–3 digits).
pos_data.card (retry)
{
"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.

formatStringrequired
PIN block format. Supported values: ISO-0, ISO-1, ISO-4.
blockStringrequired
Encrypted PIN block received from the terminal. 16 hex chars for ISO-0/ISO-1; 32 hex chars for ISO-4.
zone_idStringrequired
Identifier of the encryption zone (assigned during terminal onboarding).
key_idStringrequired
Identifier of the encryption key within the zone (assigned during terminal onboarding).
pos_data.pin_block
{
"pos_data": {
"pin_block": {
"format": "ISO-0",
"block": "D766AAA13ED5CA50",
"zone_id": "pos-gateway",
"key_id": "0001"
}
}
}

POS Data — Terminal (Retry)

idStringrequired
Terminal identifier, alphanumeric, 1–8 characters.
typeStringrequired
Terminal type: pos or softpos.
attendedBooleanrequired
true for attended terminals, false for unattended. For softpos, must be true.
capabilitiesArray of Stringrequired
Entry / verification modes the terminal supports. See the Payment API Request section above for the allowed values per terminal type.
pos_data.terminal (retry)
{
"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
Authorization parameters are identical to Payment API parameters. The authorized amount must be captured later using the Capture API.
Example 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_idStringrequired
ID of the authorized transaction to capture
api_keyStringrequired
Your API key
amountFloatrequired
Amount to capture. Partial captures are supported — you can capture less than the authorized amount, but not more.
Example Request
POST /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_idString
ID of the captured transaction
status_codeInteger
Status code of the transaction
statusString
Status of the transaction
order_idString
Order ID of the transaction
messageString
Optional additional information about the transaction result
card_last_fourString
Last four digits of the card number
card_brandString
Card brand (e.g. VISA, MASTERCARD)
error_codeInteger
Error code for the response
Example Response
{
"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_keyStringrequired
Your API key
payment_typeStringrequired
cardpos
order_idStringrequired
Any alphanumeric string to identify the Merchant's order
amountFloatrequired
Amount of the transaction including all taxes and shipping fees
currencyStringrequired
3 letter currency code
merchant_referenceString
Reference for the payout
postback_urlStringrequired
The URL for updates about transaction status are posted
Example Request
POST /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_idString
ID of the created transaction
status_codeInteger
Status code of the transaction
statusString
Status of the transaction
order_idString
Order ID of the transaction
error_codeInteger
Error code for the response
Example Response
{
"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:

  1. Prompt the cardholder for PIN.
  2. Encrypt the PIN with the terminal's encryption keys.
  3. Retry the transaction including pos_data.pin_block and pos_data.type.sequence: "subsequent".

switch_interface

Returned when the issuer requires switching from contactless to chip. The terminal should:

  1. Prompt the cardholder to insert the card.
  2. Read the card via the chip interface.
  3. 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_idString
ID of the transaction
payment_typeString
Payment type of the transaction
status_codeString
Status code of the transaction
statusString
Status of the transaction
order_idString
Order ID of the transaction
messageString
Optional additional information about the transaction result
additional_transaction_dataString
Additional transaction data provided by you. This will be shown in the dashboard as well as when you query for transaction data. It will also be sent back to your postback_url as part of the postback data.
card_last_fourString
Last four digits of the card number
card_expiry_yearString
Expiry year of the card
card_expiry_monthString
Expiry month of the card
card_brandString
Card brand (e.g. VISA, MASTERCARD)
card_typeString
Card type (e.g. CREDIT, DEBIT)
card_countryString
Issuing country of the card
included_feesString
Included fees for the transaction
external_transaction_idString
External transaction ID from the processor
checksumString
Checksum for postback signature verification
Example Postback
{
"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

FieldValue
card.number4761739001010010
card.expiry_month12
card.expiry_year2027
card.track2_data4761739001010010D27121200000000000F
card.emv_data9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000

Sandbox SoftPOS terminal

FieldValue
terminal.id87654321 (replace with the id your onboarding manager provides for your tenant)
terminal.typesoftpos
terminal.attendedtrue
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.

note

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.