The hierarchy (memorize this)
billing_id are rolled up as one line on that invoice (not separate invoices per org). Example: three orgs with billing_id: 1 → one combined line to your finance team. → Billing
Organization = one of your customers. You set reference_id to your internal client ID. Most EMSs map 1:1 (one org per client), but you can split one client into multiple orgs if you need different webhook configs or card type filters. → Organization
Card Holder = a person. You set reference_id to your internal user ID. Two ways to onboard: email (user signs with eID) or identity_id (instant, person already in OpenCard). → Card holder · Onboarding
TPA (Transaction Processing Authorization) = legal doc the client’s signatories sign saying “yes, our card data can flow to this EMS via OpenCard.” → TPA
PDPC (Personal Data Processing Consent) = GDPR consent the individual cardholder signs saying “yes, my transactions can be shared.”
Two legal docs, two audiences
OpenCard handles all of this. For new users you provide an email — we send the link, they sign with eID. For users already in OpenCard you pass
identity_id and skip the wait entirely.
The full onboarding sequence
Step-by-step for EMS integrators (APIs, phases, checklist) → Customer onboardingRuntime: what happens on a purchase
- Cardholder buys coffee ☕
- Issuer sends
authorizedtransaction state to OpenCard - OpenCard normalizes the data, checks org/webhook config
- Your webhook gets
card.transaction.authorizedwithin seconds - If merchant is receipt-enabled → OpenCard requests receipt match
- 3–5 days later issuer sends
clearedstate - Your webhook gets
card.transaction.cleared— this is the accounting truth - Maybe
receipt.fetched,transaction.true.vat,transaction.line_itemsfollow
What you build vs what OpenCard builds
Reference IDs — your best friend
Every organization and card holder has areference_id you define. Put your internal ID there. Every webhook payload includes it. Zero lookup tables needed.
Client already has another transaction feed?
Common during rollout. Your client enables OpenCard with the issuer — they do not have to disable an existing connection first, and you are not responsible for that. If they want one feed only, the client coordinates with the issuer. OpenCard sendsauthorized events (many other integrations do not) and replays history on card_holder.identified. Deduplicate cleared events with card_issuer_reference when merging with your existing store.
→ Current card issuer integration
