ADR-0011 — Stripe Terminal as the card processor
- Status: Accepted
- Date: 2026-04-28
- Decision-makers: Tom Anderson
Context
Bike shops need in-person card processing — tap, chip, swipe — at the counter. Three options for the BC Canadian market:
- Stripe Terminal (BBPOS WisePOS E, S700) — modern API, good docs, supports Canadian merchants, decent Interchange-plus pricing
- Helcim — Canadian-owned, very good Canadian rates, modern API, smaller terminal ecosystem (Smart Terminals)
- Square Terminal — strong UX, US-first; Canadian rates less competitive than Helcim/Stripe; less integration flexibility
- Moneris — Canadian incumbent, legacy enterprise tooling, no modern API worth integrating
The processor decision affects:
- Per-shop cost of accepting cards (interchange + processor fee)
- Hardware purchase / lease arrangement
- Integration complexity (how the Worker talks to the reader)
- Refund / dispute / payout flows
- Onboarding friction for new shops
Each shop owns its own merchant account, so Helm doesn't carry their card volume on its balance sheet. Money flows shop → processor → shop's bank, never through Kvick.
Decision
Use Stripe Terminal as the default card processor. Specifically:
- BBPOS WisePOS E hardware (Canada-supported; ~$300 CAD per unit)
- Per-shop Stripe account (Connect Standard for the platform relationship, but each shop's account is their own)
- Per-shop Stripe Reader Locations and Reader registrations
- Helm calls Stripe via
fetch()to/v1/payment_intentsand/v1/terminal/readers/{id}/process_payment_intent - Idempotency keys on every charge
- Webhook signature verification on every webhook
- Stripe holds the PCI scope; Helm sees no raw card data
Helcim remains an option for shops with high Canadian volume where the Stripe rate is uncompetitive. The integration would be in a separate adapter (src/lib/helcim.js) and shop config would pick which to use. v0.1 ships Stripe only.
Consequences
Positive:
- Best documentation and SDK ergonomics
- Stripe's webhook + idempotency story is mature and well-trodden
- Modern API matches the rest of our integration patterns (boring tech — Stripe is boring in the good sense)
- Hardware is widely available
- Stripe Connect Standard means each shop has their own dashboard, payouts, and disputes
Negative:
- Stripe's Canadian rates are not the cheapest; Helcim beats them
- Stripe Reader hardware lock-in (the API works only with their terminals)
- Stripe's Canadian compliance forms are extensive at onboarding (mitigated by Connect Standard, where Stripe handles most of it)
Mitigations:
- Document the Helcim option for shops that ask
- The adapter pattern (
src/lib/{processor}.js) keeps swap cost reasonable - Stripe's reader hardware is good; the lock-in is acceptable for the integration quality
Notes
For e-commerce (the shop's public site → Helm) we use Stripe Checkout, not Terminal. Same vendor, different product, same adapter file.
See also
- AI integration — separate concern, Anthropic adapter
- Slice 5 — Transactions & Payments
- Tech stack summary