# Payments & Strong Customer Authentication

Every payment passes through one gate: two independent authentication factors, cryptographically
tied to the exact amount and payee. BaxPay's terminals implement the gate — you just need to
know what it guarantees.

Under PSD2 (RTS EU 2018/389) a payment needs **two factors from different categories** — knowledge
(a PIN), possession (a device), or inherence (a biometric) — and those factors must be
**dynamically linked** to the amount and the payee. This page explains how BaxPay runs that flow,
so the statuses and webhooks your integration sees make sense. None of it is yours to implement:
your till or pump opens a [session](https://developers.baxpay.com/terminal-api), the terminal does the rest, whatever tender
the shopper picks — card, contactless, QR, or fingerprint.

## The flow, end to end

**1. Your system declares the amount**

A till, a pump, or your backend opens a payment session with the total. The payment is
`PENDING` and an SCA challenge opens. No money has moved.

**2. The terminal authenticates the customer**

The shopper presents their tender. For a fingerprint payment the terminal identifies them
(inherence) and takes a PIN (knowledge); for cards, the usual chip-and-PIN or contactless
rules apply. Two independent categories, collected on certified hardware.

**3. Dynamic linking is verified**

The authentication is bound to a hash of the user, amount, currency and payee. At capture,
BaxPay recomputes that hash from the transaction actually executing — a challenge approved
for €47.30 at Store A can never authorize €500 to someone else.

**4. Capture**

With SCA satisfied, the payment captures and the session reports `CAPTURED`. Money moves
here — and the challenge is consumed, so it can't pay twice.

> **Identification is not authorization**
> A fingerprint match (or a card read) answers *who is paying* — it is never, by itself,
> permission to charge. BaxPay's terminals enforce the separation; if you ever inspect session
> detail, trust the payment/SCA **status**, never an identification result.

## What your integration actually sees

Your surface is deliberately small:

- **Open and read sessions** through the [Terminal & Session API](https://developers.baxpay.com/terminal-api) with your
  `bxc_` connection credential. Poll until `final: true`; `CAPTURED` is the only "paid" outcome.
- **Webhooks** ([signed](https://developers.baxpay.com/webhooks)) push `payment_session.captured`, `.preauthorized`,
  `.declined`, `.voided` and `.expired` to your backend as they happen.
- **Settlement** rolls captured payments into daily batches — see
  [Settlement & reconciliation](https://developers.baxpay.com/reconciliation).
- In the sandbox, drive outcomes yourself with the
  [simulate endpoint](https://developers.baxpay.com/sandbox) — `APPROVED`, `DECLINED` or `TIMEOUT` — no terminal needed.

> **Session amounts are integers, in minor units**
> On the in-store session API, `amountMinor: 4730` means €47.30, never a float. Payment links,
> e-invoices and products use decimal euros instead (`47.30`); see
> [conventions](https://developers.baxpay.com/conventions#amounts).

## Exemptions

Some transactions legally skip the two-factor ceremony; the terminal applies these rules
automatically and your session outcome doesn't change shape:

- `Low value` (RTS Art. 16):
  ≤ €30 individually, subject to a cumulative cap (€100) and a consecutive-transaction cap (5).
  The challenge is exempt and immediately capturable.
- `Credit transfers`:
  Never exempt, at any amount.
- `Transaction Risk Analysis` (Art. 18):
  Not offered. It requires an audited fraud-rate baseline we don't claim to have.

## Idempotency

Every money-moving call in the platform requires an `Idempotency-Key` header, and retries with
the same key are safe: you get the original result back rather than a second charge. If your
till times out mid-session, retry with the same key, then reconcile with the session's status.

> **Integration checklist**
> Open sessions with your own reference (`saleReferenceId`) so reconciliation is trivial ·
> subscribe to `payment_session.*` webhooks and verify signatures · treat `CAPTURED` as the only
> "paid" signal · send an `Idempotency-Key` on every mutating call and reuse it on retries.
