Skip to main content

The hierarchy (memorize this)

Account = your OpenCard partner account. One per EMS. Billing = invoice recipient for your OpenCard bill. Organizations that share a 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.” 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 onboarding

Runtime: what happens on a purchase

  1. Cardholder buys coffee
  2. Issuer sends authorized transaction state to OpenCard
  3. OpenCard normalizes the data, checks org/webhook config
  4. Your webhook gets card.transaction.authorized within seconds
  5. If merchant is receipt-enabled → OpenCard requests receipt match
  6. 3–5 days later issuer sends cleared state
  7. Your webhook gets card.transaction.clearedthis is the accounting truth
  8. Maybe receipt.fetched, transaction.true.vat, transaction.line_items follow

What you build vs what OpenCard builds

Reference IDs — your best friend

Every organization and card holder has a reference_id you define. Put your internal ID there. Every webhook payload includes it. Zero lookup tables needed.
Map straight to your DB. Done. 🎯

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 sends authorized 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