Find-or-create customer + post transaction in one call
Resolves the customer in this fixed priority order:
- card_serial → POS barcode or legacy pass serial → customer
- external_ref → (orgId, externalRef) lookup
- email (case-insensitive)
- phone (exact string)
First match wins. On miss, creates a customer when
create_customer_if_missing is true (the default).
The transaction.external_transaction_id field is enforced as
permanently unique per (orgId, externalTransactionId). A
repeat call with the same id returns the existing transaction
at HTTP 200 instead of double-crediting, no matter how long
has passed. Use this for POS-side stable ids (Toast order #s,
Shopify checkout ids, Square payment ids). Test and live
transactions cannot share the same value; a cross-environment
replay is rejected with 422.
Idempotency-Key (24h replay cache) and
external_transaction_id (permanent dedupe) coexist — use
both for full robustness.
With a test credential this endpoint never creates a customer or enrolment. Resolve an existing record and card first, then post the isolated transaction. A missing customer or enrolment returns 404.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Replay-safe request key. Repeated requests with the same value within 24h return the original response unchanged.
255Body
Customer identifier block. At least ONE field must be present. Resolution order is fixed: card_serial → external_ref → email → phone. First match wins.
Optional. Defaults to the org's single ACTIVE card. If
multiple ACTIVE cards exist, this is required (else 400
ambiguous_default_card).
Fields used when create_customer_if_missing is true and no existing customer matches the identifier.
Response
Existing transaction returned (external_transaction_id dedup hit).
Related topics
Find-or-create customer + enrolment (no transaction)Build a POS integrationAuthentication and scopesPost a transaction (stamp / redeem / adjust)Reverse a previously-posted transaction
