Adapter contract
The PlatformAdapter interface is the seam between UCRM and your casino platform. Every casino platform has its own bonus engine, KYC flow, and webhook scheme; we don't try to be every platform's API — we provide a stable contract that platforms implement once.
For the full spec, see Adapter integration. This page is the conceptual overview.
Interface
interface PlatformAdapter {
readonly slug: string; // 'acme-prod', 'zero', ...
readonly displayName: string;
readonly capabilities: AdapterCapabilities; // declares what it supports
bonus?: BonusOps; // grantBonus, cancelBonus, getBonusStatus
kyc?: KYCOps; // initiateKYC, queryKYCStatus, updateKYCStatus
rg?: ResponsibleGamingOps; // setSelfExclusion, setLimit, etc.
wallet?: WalletOps; // getBalance, snapshot streams
}
Each ops bag is optional. An adapter that doesn't support KYC just leaves kyc undefined — the registry won't route any KYC ops to it.
Capabilities
Every adapter declares static capabilities:
interface AdapterCapabilities {
verticals: readonly Vertical[]; // casino, sportsbook, ...
bonus: { issue, cancel, query_status } // booleans
kyc: { initiate, query, update, webhooks }
rg_features: readonly RGFeature[];
wallet: { balance_pull, balance_push }
signature_scheme: "hmac_sha256" | "hmac_sha512" | "rsa";
}
Effective capabilities = tenant.config ∩ adapter.capabilities. If the tenant wants deposit_limit_daily but the adapter doesn't support it, the feature falls back to CRM-only enforcement (capability_mock pattern) — the limit is tracked in CRM, but the platform isn't told about it.
Bidirectional flow
Every domain (bonus / KYC / RG) follows the same pattern:
CRM → Adapter (outbound):
- Sync HTTP call from the bonus engine / admin action.
- Returns
platform_*_idwe persist for correlation.
Adapter → CRM (inbound):
- Webhook hits
POST /v1/adapters/:slug/webhooks/{bonus,kyc}-events. - HMAC-SHA256 over
<timestamp>.<body>(Stripe-compatible). - Idempotency dedupe via
webhook_events_processed (adapter_slug, event_id). - State sync: lifecycle events update domain state under RLS context.
Adapter Zero — the reference
Adapter Zero is the in-process synthetic adapter we ship for testing + demos. It declares maximum capabilities (every vertical, every KYC flow, every RG feature) so tests exercise the full surface. Real-platform adapters declare narrower capabilities — what the platform actually supports.
Adapter Zero plays both sides: when CRM calls adapter.bonus.grantBonus(), AdapterZero queues a synthetic webhook back through the receiver via fastify.inject(). Same code paths as a real HTTP roundtrip — HMAC verification, idempotency, state sync — without the network.
Adding a new adapter
Three steps:
- Create
services/adapters/<your-platform>/with the canonical event mapping (your platform's events → UCRM canonical events). - Implement the
PlatformAdapterinterface inapps/api/src/lib/bonus-adapter-<your-platform>.ts(or your own service). - Register the adapter by slug in
bonus-adapter-registry.ts+ add the HMAC secret resolver inbonus-webhooks.ts.
That's it. A complete adapter is ~200-400 lines of TypeScript.