Перейти до основного вмісту

Webhooks API

UCRM is both a webhook sender (outbound from journeys) and a webhook receiver (inbound from casino platforms + messaging providers).

Inbound — bonus events

POST /v1/adapters/:slug/webhooks/bonus-events

Casino platform → CRM. Lifecycle events for bonus_grants. See Adapter integration / Bonus flow for full schema.

Headers:

  • X-UCRM-Signature: <hex(hmac_sha256(secret, "<ts>.<body>"))>
  • X-UCRM-Timestamp: <unix-seconds> (anti-replay; 5-min window)
  • Content-Type: application/json

Body:

{
"event": "bonus.completed",
"event_id": "uuid", // idempotency key
"ts": "2026-05-08T12:00:00Z",
"grant_id": "uuid", // CRM's bonus_grants.id
"platform_bonus_id": "platform-side-id",
"data": { ... } // event-specific
}

Response:

  • 200 { received: true, applied: true | false, new_status: "..." } — accepted (delivered or replay)
  • 401 FORBIDDEN — bad signature / timestamp out of window
  • 404 NOT_FOUND — unknown adapter slug or grant_id
  • 422 VALIDATION_ERROR — malformed payload

Inbound — KYC events

POST /v1/adapters/:slug/webhooks/kyc-events

Same auth scheme. Body:

{
"event": "kyc.approved", // submitted | approved | rejected | expired | level_upgraded
"event_id": "uuid",
"ts": "2026-05-08T12:00:00Z",
"player_external_id": "player_001", // resolved to UCRM player_id by lookup
"level": 2,
"data": { "reason": "...", "expires_at": "..." }
}

Important: rejected with 403 when tenant.kyc_model in {crm_owns, none} — those tenants own KYC themselves; UCRM doesn't accept inbound updates.

Inbound — provider delivery webhooks

Per-provider, scoped to messaging:

  • POST /v1/messaging-webhooks/postmark — Postmark email delivery / open / click / bounce
  • POST /v1/messaging-webhooks/twilio — Twilio SMS status callback
  • (FCM doesn't push delivery webhooks; client SDK reports push_opened / push_clicked via the regular /v1/events path.)

Each provider has its own signature scheme — see Adapter integration / Security.

Outbound — journey webhook nodes

Journeys can fire webhooks via the call_webhook node. See Journeys feature.

UCRM's outbound webhook is signed identically to the inbound scheme (HMAC-SHA256 over <timestamp>.<body>), so an operator who wires a UCRM-side endpoint as the journey target can use the same shared secret on both legs.

Idempotency ledger

webhook_events_processed is the dedupe table — (adapter_slug, event_id) PK. Replays are detected pre-route and return 200 { applied: false, replay: true } immediately.

Bonus reconciliation

If webhooks drop, pnpm --filter @ucrm/api reconcile:bonuses (daily cron) walks active grants + asks each adapter for the platform's current view via adapter.bonus.getBonusStatus(). Replays missing terminal transitions through the same state-sync pipeline.