Skip to main content

Receipt Compliance

Card schemes (Visa, Mastercard, Discover, Amex) require that a receipt be available to the cardholder on demand for every transaction where a card is read — including declined and failed transactions. Delivery method is your choice — email, SMS, printed receipt, or an in-app receipt screen. The requirement is availability, not a specific delivery channel.

Declines and failures are included

A cardholder must be able to request a receipt even for a declined transaction. They need written proof that no charge was made — and a reference for any dispute. You do not need to print automatically for every decline, but the merchant must be able to provide one on request.

The only exception is a transaction that never completed a card read (e.g. the cardholder tapped away before the terminal finished reading the chip). If no EMV data was captured, there is nothing to put on the receipt.


Required fields​

Include all of the following in every customer-facing receipt. Fields marked Conditional are required only when present in the transaction result (non-null and non-empty).

FieldSource in resultConditionNotes
Date and timeterminalDateTime (local) or serverDateTime (UTC)AlwaysDisplay in cardholder's local time zone
Transaction typetype (SALE, REFUND, REVERSAL, MOTO_SALE, etc.)Always
OutcomefinStatus + statusMessageAlwaysstatusMessage is in cardholder's language — display it, don't parse it
Amount chargedtotalAmount + currencyAlwaysUse totalAmount — not requestedAmount. On partial approvals these differ.
Card schemecardSchemeName or cardTypeNameAlwayse.g. "Visa", "Mastercard"
Masked card numbermaskedCardNumberAlwaysLast 4 digits minimum
Authorisation codeauthorisationCodeAlwaysRequired for disputes
Issuer responseissuerResponseCode + issuerResponseTextAlwayse.g. "00 / Successful"
Transaction IDtransactionIDAlwaysRequired for Handpoint Support escalation
Retrieval referencerrnConditionalNumeric string, up to 13 chars. Present on card-present sales (CHIP, contactless, swipe); empty on refunds, reversals, and MOTO. Required for chargebacks when present.
AIDaidConditionalHex string, exactly 14 chars for Visa and Mastercard (their registered AID values are fixed-length). EMV spec allows up to 32 chars for other schemes. Present on CHIP (insert) and CHIPCONTACTLESS — empty on swipe/MOTO.
TVRtvrConditionalHex string, always exactly 10 chars (5 bytes, EMV-defined fixed length). Present on CHIP and CHIPCONTACTLESS — empty on swipe/MOTO.
TSItsiConditionalHex string, always exactly 4 chars (2 bytes, EMV-defined fixed length). Present on CHIP insert only — empty on CHIPCONTACTLESS even though the chip is read. Empty on swipe/MOTO.
IADiadConditionalHex string, scheme-dependent fixed length: 14 chars for Visa, 36 chars for Mastercard. Present on CHIP and CHIPCONTACTLESS — empty on swipe/MOTO.
ARCarcConditionalHex string, always exactly 4 chars (2 bytes, EMV-defined fixed length). "0000" = online approval; "1000" = terminal/gateway decline (capability restriction or routing error). Empty on MOTO.
Merchant nameYour merchant recordAlwaysFull legal name
Merchant addressYour merchant recordAlwaysFull address
MIDmidAlwaysMerchant ID at acquirer
TIDtidAlwaysTerminal ID at acquirer
transactionReferencetransactionReferenceSuggestedISV's UUID — useful for troubleshooting; link to your internal order
Serial numberYour terminal configSuggestedLinks to device in dispute resolution
Use totalAmount, not requestedAmount

On partial approvals, requestedAmount is what the customer owed and totalAmount is what the card actually covered. Always use totalAmount as the amount on the receipt — that is the amount that will settle.


Fee mitigation — one rule per program​

A transaction that carried a fee needs one more line, and the rule differs by program. Read fee.mitigationProgram and fee.applied on the result, then apply the matching row. See Fee Mitigation for the full contract.

ProgramThe receipt showsCondition
SurchargeA separate line, clearly labelled. The card networks require it. Never inside the total, never mixed with the taxfee.applied is true
Admin feeA separate line, with its own labelfee.applied is true
Dual pricingNo fee line. The card price is the posted priceAlways
Cash discountNothing. It is not a card transactionNever reaches the gateway

The amount on the line is fee.amount from the result, in major units. A fee the gateway dropped (fee.applied is false) gets no line at all, because the customer never paid it.

Dual pricing prints no fee line, on purpose

This looks like an omission. It is not. An itemised fee would present a price as a fee, and would undermine the model that makes dual pricing lawful. Do not add a fee line to a dual pricing receipt.


Receipt language​

The two receipts render in different languages:

ReceiptLanguage source
customerReceiptCard's language preference (cardLanguagePreference field, e.g. "es_ES")
merchantReceiptTerminal's configured merchant language

A Spanish-language card tapped on an English-configured terminal produces a Spanish customer receipt and an English merchant receipt. This is the expected behaviour — the customer receipt renders in the cardholder's language.


Receipt delivery​

Handpoint provides a hosted receipt URL in merchantReceipt and customerReceipt fields for card-present transactions. Display or link to the customer URL; the merchant URL is for your own records.

URL format:

https://receipts.handpoint.com/receipts/{transactionID}/customer.html
https://receipts.handpoint.com/receipts/{transactionID}/merchant.html

The path uses transactionID (the gateway-assigned GUID from the result), not transactionReference.

Fetch the URL and present it in a webview, email it as a link, or send it via SMS. The hosted receipt is pre-formatted and compliant — you can use it as-is.

Handle both URL and raw HTML​

The merchantReceipt and customerReceipt fields in the transaction result contain either:

  • A hosted URL (https://receipts.handpoint.com/...) — fetch and display or include in email/SMS
  • Raw HTML string — rendered directly when the terminal could not upload to the receipt server

Your code must handle both. Never assume it's always a URL.

function displayReceipt(receiptField) {
if (receiptField && receiptField.startsWith('http')) {
// Hosted URL — fetch and render in webview, or email the link
openWebview(receiptField);
} else if (receiptField) {
// Raw HTML — render directly
renderHtml(receiptField);
} else {
// No receipt available — build from result fields (see below)
buildReceiptFromResult();
}
}

When raw HTML is delivered (not a URL)​

ScenarioWhy
MOTO on-terminal (moToSale)Terminal has no receipt upload path for keyed-entry MOTO
Network failure during transactionTerminal could not reach the Handpoint receipt server at transaction time

Known gap — recovered transactions​

No receipt URL for recovered transactions

When a transaction is recovered via GET https://transactions.handpoint.com/transactions/{transactionReference}/status (after a network failure or app crash), the response does not include merchantReceipt or customerReceipt fields.

You must build the receipt yourself using the other fields in the /status response.

Building a receipt from /status​

Use the required fields table above with the values from the /status response. All the required fields (transactionID, totalAmount, authorisationCode, maskedCardNumber, rrn, terminalDateTime, cardSchemeName, etc.) are present — only the pre-built HTML receipt is absent.

Apply your standard receipt template and populate it from the response fields. For EMV fields (AID, TVR, IAD, ARC): include each one only if its value is non-empty in the response.


Acquirer-specific notes​

AcquirerNotes
EPIHosted receipt URL returned for card-present. Raw HTML for MOTO on-terminal.
EmerchantPay / PaystraxHosted receipt URL returned. Check whether merchantReceipt / customerReceipt are present — may vary by transaction type.
PAYSAFEReceipt field behaviour follows the same pattern — URL when upload succeeds, raw HTML as fallback.

Testing receipt delivery​

ScenarioExpected
Standard card-present sale — approvedmerchantReceipt and customerReceipt are hosted URLs — display or send to cardholder
Standard card-present sale — declinedmerchantReceipt and customerReceipt are hosted URLs — receipt still available and must be offered to cardholder on request
MOTO on-terminal saleReceipts are raw HTML strings (not URLs)
MOTO remote sale (POST /moto/sale)No merchantReceipt / customerReceipt in response — build from result fields
Transaction recovered via /statusNo receipt fields — ISV-built receipt required
Email deliveryCardholder receives receipt link within 30 seconds
Printed receipt (PAX with printer)All required EMV fields printed; no truncation

Receipt retention​

Suggested lifetime: 13 months, matching Handpoint Gateway's transaction processing data retention period.

Historical analytics data (Transaction Feed API) has no specified retention limit — transaction records are available indefinitely for reporting and dispute resolution.