View as Markdown

llms.txt

This guide isn't available right now

This instance couldn't load its guide catalog. The guide returns as soon as the catalog is readable again.

Back to the guides

No such guide

This instance publishes no guide under that address. It may have been renamed, or it may belong to a feature this installation hasn't enabled.

Back to the guides

That guide is part of the product documentation

This guide is written for someone operating WinkPG through its screens rather than integrating against it, so it lives in the application's own help section instead of here. Sign in to WinkPG and open Help to read it.

Back to the guides

Guides Payments

Card-present payments over the API

What a terminal application sends on the transactions API for a magnetic stripe, chip, or contactless read, which reader encryption needs setup first, how to identify the terminal, and how to attribute a webhook to it.

This guide is for developers writing a terminal application that reads a card at a counter, a lane, or a handheld device and sends the read to WinkPG. It covers the fields that make a transaction card-present, what reader encryption needs set up before the first sale, how to tell which terminal took a transaction, and how a webhook receiver attributes an event to that terminal.

Read Quickstart: Direct API first if you haven't taken a payment through the transactions API yet. Everything here is an addition to that request.

When this applies

This guide applies when the terminal application calls the transactions API directly and WinkPG authorizes the payment with the processor. The terminal reads the card, builds the create request, and reads the result from the response.

There's nothing terminal-specific to set up on the API side:

  • No terminal endpoint. A card-present sale is a POST to /api/transactions, the same create request every other payment uses.
  • No device registration. WinkPG doesn't keep a list of devices, and a new terminal doesn't need to be enrolled before it sends its first sale.
  • No per-device credential. The merchant's API key, with the transactions:write scope, is the whole handshake. Every terminal the merchant runs can send with the same key, or you can issue one key per site or per device if you want to revoke one without affecting the others.

A terminal that authorizes with the processor itself and then reports the finished transaction to WinkPG is a different model, and this guide doesn't describe it.

What the merchant configures first

Two things on the merchant's processor profile decide whether a card read reaches the processor as a card-present transaction. Both are set once, by whoever boards the merchant, and apply to every terminal. Neither is configured per device.

  • An active processor profile with a card-present industry, such as Retail or Food/Restaurant. Routing doesn't look at the entry mode, so a card-present request goes to whichever profile the merchant's routing selects. The processor message is built for that profile's industry: on a profile set to Electronic Commerce or Direct Marketing, the message isn't a card-present one, and the chip data may not be sent at all.
  • The processor's terminal number on that profile. Depending on the processor, the field is labeled Terminal Number or Terminal ID. It's the value the processor assigned to the merchant's terminal configuration, and every terminal application sending through the profile shares it.

A merchant with no active processor profile can't take any payment. The create request comes back with the ProcessorNotConfigured result code.

The request

A card-present request is the ordinary create request with three additions: the entry mode, the data the reader produced, and a deviceData block describing the device.

Entry mode

cardData.entryMode says how the card was read on this transaction. It's what makes the transaction card-present, so always send it from a terminal.

entryMode Send it when
Manual The card number was keyed on the terminal. A keyed number is processed as a card-not-present entry unless you also set cardholderPresence (see below).
UnencryptedCardReaderSwipe The magnetic stripe was read and the reader produced cleartext track data.
EncryptedCardReaderSwipe The magnetic stripe was read and the reader encrypted the track data.
Icc The chip was read by contact (a dip).
Proximity The card or phone was tapped (contactless).
Fallback The chip couldn't be read, so the magnetic stripe was read instead.
TechnicalFallback The chip couldn't be read because of a fault in the chip or the reader, so the magnetic stripe was read instead.
EmptyCandidateFallback The chip was read, but the card and the terminal share no application, so the magnetic stripe was read instead.

Every value except Manual classifies the transaction as card-present. Leaving entryMode out stores it as Unknown, and the processor message then infers presence from the profile's industry instead of from the read. For a terminal read, that inference is the wrong place to start.

Cleartext read fields

When the reader hands you the card data in the clear, send it on these fields. The encrypted case is in Encrypted reads below.

Field Carries Required
cardData.trackData The track data from a magnetic stripe read. For UnencryptedCardReaderSwipe, unless you send emvData instead.
cardData.emvData The chip data the reader produced, as a TLV string. For Icc and Proximity.
deviceData.cvmResults The cardholder verification method the reader used: 1 for offline PIN, 2 for online PIN, 3 for signature. No. Send it when the reader reports it and the chip data has no tag 9F34. WinkPG reads it only as a fallback for that tag.

A request whose fields don't match its entry mode is rejected with HTTP 400 and a CardData: code. For example, Icc with no emvData returns CardData:EmvDataRequiredForIccOrProximity, and UnencryptedCardReaderSwipe with neither trackData nor emvData returns CardData:TrackOrEmvRequiredForUnencryptedSwipe.

Cardholder presence

cardholderPresence describes whether the cardholder is at the point of sale. That's a different question from how the card was read. Its values are CardPresent, MOTO, ECommerce, and Recurring.

Leave it unset for a magnetic stripe, chip, contactless, or fallback read. WinkPG infers CardPresent from any of those entry modes, which is the right answer.

Set it when the inference would be wrong. The common case is a keyed entry at a counter: with entryMode set to Manual, WinkPG infers MOTO, so a cardholder standing at the terminal needs cardholderPresence set to CardPresent explicitly.

Terminal capability

cardData.terminalCapability declares what the terminal hardware can read, which can differ from how this card was read. Its values are MagneticStripe, MagneticStripeWithPin, Chip, ChipWithPin, ChipContactless, and ChipContactlessWithPin.

It's optional. Leave it unset and the processor message carries the processor's default capability. Set it when the terminal is stripe-only, so the processor doesn't see a chip capability the device doesn't have. A stripe-only capability combined with a chip, contactless, or fallback entry mode is a contradiction, and it's rejected with HTTP 400 and CardData:EntryModeIncompatibleWithTerminalCapability.

Device data

The deviceData block holds two kinds of field, and they behave differently.

These three fields are telemetry. WinkPG stores them and shows them back, and they don't change how the payment is processed:

Field Carries
deviceData.serialNumber The device's serial number. This is the field that identifies the physical device; see Identifying the terminal.
deviceData.sdkVersion The version of the terminal application or the reader SDK.
deviceData.batteryLevel The battery level, as a whole-number percentage, for a device that reports one.

These two fields change processing:

Field Effect
deviceData.isEncrypted true tells WinkPG that every card data field on the request holds ciphertext, including emvData. Defaults to false.
deviceData.encryptionType The scheme the reader encrypted with. It selects the decryption path; see Encrypted reads.

[!WARNING] Setting isEncrypted to true on a cleartext read makes WinkPG treat emvData as an opaque encrypted payload instead of TLV. The chip data isn't parsed, so the card application isn't identified from it.

Example

A cleartext chip read, sent from lane 4:

curl -X POST "https://your-gateway-host/api/transactions" \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionType": "Sale",
    "idempotencyKey": "lane-04-000123",
    "merchantReference": "TICKET-000123",
    "register": {
      "id": "00000000-0000-0000-0000-000000000004",
      "name": "Lane 4"
    },
    "cardData": {
      "entryMode": "Icc",
      "emvData": "EMV_TLV_FROM_THE_READER"
    },
    "deviceData": {
      "serialNumber": "DEVICE_SERIAL_NUMBER",
      "sdkVersion": "TERMINAL_APP_VERSION",
      "isEncrypted": false
    },
    "invoiceData": {
      "amounts": { "base": 10.00, "total": 10.00 }
    }
  }'

EMV_TLV_FROM_THE_READER stands for the TLV string the reader returned for this one read. Never build it by hand or reuse one from an earlier read: the chip produces a new cryptogram for each authorization.

Encrypted reads

When the reader encrypts the card data, set deviceData.isEncrypted to true, set deviceData.encryptionType to the reader's scheme, and send the key serial number the reader reports on cardData.keySerialNumber. The ciphertext goes on these fields:

  • cardData.encryptedTrack2Data, plus encryptedTrack1Data when the reader produces it. This is the only payload WinkPG decrypts itself, so every scheme it decrypts needs it, including on a chip read.
  • cardData.emvData, for an encrypted chip or contactless read. WinkPG never decrypts this field. It's forwarded as ciphertext on the schemes that forward, and ignored by the decryption on the schemes that don't.

Whether anything has to be set up first depends on the scheme. The comparison on encryptionType ignores case and surrounding spaces.

encryptionType What it needs before the first sale What WinkPG does with the read
MAGENSA Nothing on the WinkPG side. Decrypts nothing. Forwards the encrypted tracks, the encrypted chip data, and the key serial number to the decryption service in front of the processor.
PAXDUKPT The reader is injected with WinkPG's base derivation key. That's a provisioning step with the key injection facility, not an API call. Decrypts the encrypted track 2 data with that key before authorization. If the merchant is boarded on a payment encryption provider, the read is decrypted through the provider instead, on the same terms as DUKPT below.
DUKPT or ONGUARD An administrator boards the merchant on a payment encryption provider and adds a key entry for each key serial identifier the merchant's readers use. Decrypts through the provider, using the key entry the read's key serial number matches. A key serial number with no matching entry is refused with HTTP 403 and Decryption:UnknownKeySerialIdentifier, and a read with no encrypted track data or no key serial number with HTTP 400 and Decryption:InvalidPayload. Neither creates a transaction. A merchant that isn't boarded has the read forwarded to the processor still encrypted.
Any other value Nothing on the WinkPG side. Decrypts nothing. Forwards the payload to the processor as sent.

PAXDUKPT reads the key serial number from a different place than the other schemes:

  • When the merchant isn't boarded on a provider, the key serial number is read from deviceData.serialNumber and nowhere else. A read with an empty serialNumber isn't decrypted.
  • When the merchant is boarded, cardData.keySerialNumber is read first, and deviceData.serialNumber is the fallback.

Every other scheme reads cardData.keySerialNumber only, and deviceData.serialNumber stays the device's own serial number.

If the merchant is boarded on a payment encryption provider, the Encrypted card reader payments guide in the help center covers the decryption record on the response and every refusal code to handle.

What comes back and what's stored

The response to the create request, and every later GET /api/transactions/{transactionId}, carries the transaction as stored. For a card-present sale, that includes:

  • cardData.entryMode, as you sent it. It also classifies the transaction under POS Terminal in the Entry Mode filter on the transactions list.
  • The whole deviceData block, the register, and the merchantReference.
  • Presence flags in place of the raw read: cardData.hasEmvData, cardData.hasTrackData, cardData.hasEncryptedTrackData, and cardData.hasPin.

The raw track data, chip data, encrypted tracks, PIN, and reader-generated dynamic verification value are never stored. They're used for the authorization and dropped, so a read can't be recovered from the transaction afterward, and the presence flags are the only record that the request carried them.

An abridged response for the example above:

{
  "id": "6f3b2c18-0a4d-4a9e-9d4f-2b71c2f0a911",
  "transactionType": "Sale",
  "merchantReference": "TICKET-000123",
  "register": {
    "id": "00000000-0000-0000-0000-000000000004",
    "name": "Lane 4"
  },
  "cardData": {
    "entryMode": "Icc",
    "hasEmvData": true,
    "hasTrackData": false,
    "hasEncryptedTrackData": false,
    "hasPin": false
  },
  "deviceData": {
    "serialNumber": "DEVICE_SERIAL_NUMBER",
    "sdkVersion": "TERMINAL_APP_VERSION",
    "isEncrypted": false
  }
}

Identifying the terminal

Three native fields identify where a transaction came from. Each answers a different question, and you can send all three on the same request.

Field Identifies Where you see it
deviceData.serialNumber The physical device. Returned on GET. Shown as Serial Number in the Device section of the transaction's detail page.
register.id and register.name The lane, till, or station, independent of which device is in it today. Returned on GET. Receipts print the name after TID:.
merchantReference The merchant's own ticket, order, or invoice number. Returned on GET. It's also carried to the acquirer on the clearing record, so it's the value to reconcile against on the acquirer's transaction report.

Keep merchantReference free of card numbers and other sensitive data, because it's stored on the transaction and sent to the acquirer.

For a PAXDUKPT reader on a merchant that isn't boarded, deviceData.serialNumber carries the key serial number (see Encrypted reads), so use register to identify the terminal instead.

Custom fields are a fourth option, for any other value you want to search or report on. The field has to be defined and turned on for the merchant first: once a merchant has at least one custom field turned on, a create request naming a field that isn't one of them is rejected with HTTP 400. See Transaction custom fields for how to define them.

Webhooks

Every transaction lifecycle event fires for a card-present transaction exactly as it does for any other. WinkPG doesn't filter events by source or entry mode, so a subscription that receives Transaction.Authorized for an online payment receives it for a tap at lane 4 too.

The lifecycle event body carries the transaction identifier, the merchant identifier, the status, the amounts, the result and decline reason codes, and on Transaction.Settled the batch identifiers. It doesn't carry the device serial number, the register, or the merchant reference.

To attribute an event to a terminal, take TransactionId from the event body and read the transaction with GET /api/transactions/{transactionId}. The response carries all three identifying fields. See Webhook integration for the envelope, the signature, and retry behavior.

Refunds, voids, and reversals

A card-present sale is corrected through the same operations as any other transaction, against its transaction identifier. Nothing about the follow-up depends on the terminal. See Refunds, voids, and reversals for which operation applies at which point in the transaction's life.

What to log, and what not to

Never log track data, chip data, the PIN, or any cryptogram, in cleartext or encrypted form. They're card data, and the rules that govern a card number govern them too.

Log the transaction identifier, the entry mode, and the device serial number. Together they answer most support questions about a terminal sale: which transaction it was, how the card was read, and which device read it.

See also

Reconnecting to the server

Could not reconnect

This session has ended

Attempt 1

Your work on this page is still here. Retrying keeps it; reloading starts the page again.

The server no longer holds this page's state, so it has to be loaded again.