Joris ColleretProduct Lead / Manager
Case study 02 · Crypto payments platform · API & backend

Crypto payments for casinos: an API operators can trust, and a line the platform never crosses

A B2B platform that lets gaming operators accept crypto without running blockchain infrastructure. I made its API contract something an operator can integrate without losing money, then designed the compliance layer that keeps the platform a data provider rather than a party to the transfer.

Role
Senior Product Manager: Operator API, Admin API, compliance
Team
Core engineering, a frontend agency, leadership, custody and compliance vendors
Delivered
Contract gap report, integration guide v1.1 and v1.2, production UAT, stage environment design, V3 compliance design
Proves
API and backend literacy, risk judgment, working across engineering, vendors and compliance
Deposit status lifecycle: defined, confirmed_onchain, pending_external, completed, with failed and failed_external reconciled daily back to completed
The deposit lifecycle an operator builds against. Only completed is final; both failure statuses can still complete.

01Context

The client is an API-first B2B platform that lets gaming operators accept crypto deposits and pay out withdrawals (USDT, USDC and ETH on Arbitrum and Ethereum) without running any blockchain infrastructure. A regulated custodian holds the funds. The platform watches the chain, detects a deposit within seconds, keeps the ledger, and tells the operator what happened through webhooks and a REST API. The client is not named here.

I joined as Senior Product Manager. Three layers had to agree with each other: the core engine with its Operator and Admin APIs, a merchant portal and admin panel built by a frontend agency, and the custodian underneath. A live casino operator was weeks from production. Then regulation arrived on the roadmap: wallet screening, the Travel Rule and identity checks for crypto in gambling.

02Problem

User pain. An operator's engineers build against two documents: the OpenAPI spec and the integration guide. When I read them side by side, line by line, they disagreed in 24 places. Two were the kind that cost money: an operator following the guide to the letter would reserve the wrong amount for a withdrawal fee, or process a retried request twice. The rest were quieter traps: the same field called coin in requests and coinSymbol in webhooks, a reconciliation sample calling a filter the API does not have, a status described as final that is not.

Business pain. For a payments platform the integration is the product. Every hour an operator spends debugging a signature or a double credit is an hour it is not sending players, and every wrong sentence in the guide becomes a support ticket or a disputed balance. Compliance raised the stakes further: designed carelessly, it would make the platform the regulated party on every transfer.

For a payments API, the integration guide is part of the contract. If the guide is wrong, the API is wrong.

03Approach

Contract first. I treated the live OpenAPI spec as the contract of record and diffed every statement in the guide against it: endpoints, fields, enums, fee formulas, delivery and retry behaviour. Each disagreement became either a guide fix or a written question for engineering. Anything the spec did not cover stayed an open question, never an assumption.

Rules before chapters. The guide now opens with the six rules that lose money when they are missed:

RuleWhat goes wrong without it
The crediting trigger is the operator's decisionTreating an early status as final puts the player ledger out of step with the site balance
Deduplicate on eventId and on (txHash, logIndex), with database constraintsRetries and WebSocket duplicates double-credit the player; an application-level check loses the race
Verify the signature over the raw request bytesRe-serialised JSON fails every signature, and someone "fixes" it by skipping verification
Never rely on webhook orderOn Arbitrum a status update can arrive before the first-detection event
Neither failure status is finalA one-way adjustment cannot be undone when the deposit completes later
Integers in base units, never floatsUSDT has 6 decimals and ETH 18; float arithmetic silently corrupts balances

Test in production, without moving money. Before the operator's go-live I wrote a production UAT pack, ten flows from funding a site to settlement and exports, and ran the first pass myself on the live portal with no funds moved. It found seven issues. The one that mattered: withdrawal limits were configured per chain, while the documentation promised one limit per coin across both chains. An operator who believes a limit covers two networks when it covers one has real, avoidable exposure.

A stage environment that can reach every state. Integration tests, demos and QA all needed a held withdrawal or a reorged deposit on demand, not whenever one happened to occur. I designed Stage Control for the admin panel: a read-only catalogue of 73 scenarios, each with its expected result and its source, and a Create Transaction form that back-solves its inputs so the chosen state is genuinely reached rather than faked.

Compliance: the party before the vendor. Crypto in gambling brings wallet screening, the Travel Rule and identity checks. I compared providers slot by slot (Sumsub, Notabene and Didit among them) and wrote the deposit crediting-risk policy. But the real decision was not which vendor. It was who is the party to each transfer:

OptionForAgainst
The platform files the Travel Rule and stores player identityOne integration for every operatorMakes the platform the regulated party on every transfer, and an identity store it was designed not to be
Operators bring their own providers; the platform stays outNothing for the platform to license or secureSmaller operators have no provider, and the platform has nothing to offer them
Operators own identity and filing in their own Sumsub account; the platform screens wallets and pushes the transfer data inThe operator stays the party; the platform adds screening and data without touching fundsDepends on the vendor's terms and written consent; where identity lives for operators with no provider is still open

04Decision

  1. A guide rebuilt against the contract. Version 1.1 carried thirteen corrections, from per-chain confirmation thresholds (12 on Ethereum, 50 on Arbitrum) to a reconciliation example that finally matches the API. Version 1.2 added eight more, on native ETH and failure handling.
  2. One final status. Only completed is final. Both failure statuses are reconciled daily against custody records and can still complete, so every operator-side adjustment has to be reversible.
  3. Crediting is the operator's call. The status at which a player's balance becomes spendable is agreed per operator, never a platform default. The guide spells out what each choice exposes: crediting before completed risks gaming losses on unsettled value, never a direct cash-out of funds that did not arrive.
  4. A live question, answered in a day. A live operator saw an ETH deposit sit in a failure status and asked two things: how to key a native ETH deposit that has no token log, and whether "failed" means final. I took both to engineering, came back with a real payload, and put the answers in the guide: logIndex −1 and the zero address by convention, and daily reconciliation. The "deposit" itself turned out to be a false detection, a transfer from a new custodian wallet, which went onto the filter list.
  5. Stage Control, designed to the contract. Every form mirrors the production endpoint it simulates, down to base units and the documented decision order: the balance is checked before the approval threshold.
  6. A compliance boundary written as ten guardrails. The design holds only while all ten do. Among them: no custody and no control of funds; no transfer without an authenticated operator request; the compliance layer never triggers a sale; the platform is never the Travel Rule party in its own name; no regulator submissions, only exports the operator files. And an unknown result is never shown as clean.
Stage Control scenario catalogue: 73 scenarios with their expected results, grounding and the panel that produces them
Stage Control's scenario catalogue: 73 states the platform can reach, each with its expected result and grounding. Nothing runs from here; producing a state is a deliberate act. Scroll inside the frame.
Create Transaction form for a withdrawal, with a target state selector and a live prediction of the outcome
Create Transaction: pick the target state and the form back-solves the inputs, with a live prediction in the documented decision order.
Approval queue for held withdrawals, refusing an under-funded approval with error 4009
The approval queue refusing an under-funded approval with the same error the API returns.

05Outcome

Delivered: the contract gap report (24 findings, two of them blockers) with its questions to engineering, integration guide versions 1.1 and 1.2, the production UAT pack and its first run, and answers to a live operator's integration questions within a day. Designed, not yet built: Stage Control, whose first build step waits on how the admin panel's login is trusted by the engine. Proposed, under review: the V3 compliance design, with its last open decisions sitting with leadership and counsel.

No integration-time number to show yet, and I will not invent one. What I would track: time from sandbox key to first completed deposit, integration support tickets per operator, and webhook deliveries that fail signature checks.

What surprised me. How much backend work is vocabulary. The portal says merchant and store where the engine says operator and site; the API writes confirmed_onchain where the engine writes confirmed_on_chain. Most of the expensive mistakes I found were sentences, not code.

06Reflection

Research is not counsel. I built the first compliance drafts on regulation I had read at primary sources myself. A later review corrected eleven of my own claims, from whether a threshold applies "above" or "at or above" EUR 1,000 to which article covers incoming transfers. Every regulatory line now carries "per research" until counsel answers, and next time counsel reads the first draft.

I would find the blocking question before the third prototype. Stage Control reached its third version with the question that gates all of it still open: how the admin panel's login is trusted by the engine. Now I ask "what authenticates this?" before a screen gets drawn.

And I would lock the glossary on day one. Three layers built by different teams each named things their own way, and every term I pinned late cost a round of corrections across documents.

Stage Overview in the admin panel: read-only environment summary, engine path switch between simulated and real testnet, limits and balances
The stage environment's overview: what is true of this environment right now, the engine path (simulated or real testnet), limits and balances. Scroll inside the frame.
Next case studyTwo pages answered one question →

© 2026 Joris Colleret · Crestline Product Labs. Work shown is my own product work; proprietary details are removed or generalised. Brands belong to their owners.