Server-to-Server
With the Server-to-Server integration, your systems collect and send card-present data (PAN, EMV, Track2, and optionally PIN blocks) to OneAPI. You must be fully PCI DSS compliant.
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.
For the full sequence diagram, see Payment workflow on the Card POS overview.
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.
- Receive asynchronous postback notification to
postback_urlwith the final transaction status.
For a general walkthrough of credentials, authentication, and postbacks, see Get Started — Server-to-Server Processing.
Create a payment
POST/rest/payment
/rest/paymentProduction URL
https://api.betterpayment.de/rest/paymentTest URL
https://testapi.betterpayment.de/rest/paymentCommon 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 cardholder verification has been performed with online PIN (e.g., high-value contactless transactions).
key_derivationStringDirect (default): the key is used directly. TDES-UKPT: Triple DES, unique key per transaction (IBM CCA UKPT key management). See the nexo specification "Card Payment Protocols Security" (version 4.0), section 8.3.4 "IBM CCA UKPT Key Management".formatStringrequiredISO-0, ISO-1 or ISO-4.blockStringrequiredderivation_dataStringzone_idStringkey_idStringrequiredkey_versionString{
"pos_data": {
"pin_block": {
"format": "ISO-0",
"block": "D766AAA13ED5CA50",
"zone_id": "pos-gateway",
"key_id": "0001"
}
}
}
The fields to send depend on the payment method:
| Payment method | pin_block fields |
|---|---|
Card POS (cardpos) | format, block, zone_id, key_id |
girocard (girocard) | key_derivation: "TDES-UKPT", format: "ISO-0", block, derivation_data, key_id, key_version |
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
/rest/authorizePOST /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
POST/rest/capture
/rest/captureProduction URL
https://api.betterpayment.de/rest/captureTest URL
https://testapi.betterpayment.de/rest/capturetransaction_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
POST/rest/payout
/rest/payoutProduction URL
https://api.betterpayment.de/rest/payoutTest URL
https://testapi.betterpayment.de/rest/payoutapi_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. When the issuer requests no terminal action, action_data.new_emv_data is returned without client_action and no further API request is needed for it.
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.