Operator API — Streamer Account Provisioning
Status: Proposal · April 2026
Evaluated and approved for implementation. Legal sign-off on account type is required before building. Start with a single pilot operator.
Problem
After a deal is signed, a streamer must independently create a player account at the operator's platform, pass KYC (days), deposit or wait for balance, and only then begin streaming. This gap between "deal agreed" and "first stream" is the primary source of streamer drop-off post-deal.
Proposed Solution
Operators implement a single HTTP endpoint on their side. Verifluence calls it immediately after a deal is created. The operator provisions a player account (or fast-track onboarding link) and returns credentials. The streamer sees a "Your account is ready" card on their deal page and can begin immediately.
This is entirely optional — operators who do not implement the endpoint continue working as today.
Integration Point
Trigger: deal creation (POST /api/negotiations/:id/deal) — after the deals row is inserted and HTLC allocation is confirmed.
The call is made asynchronously by the background worker, not inline. A failed or slow operator endpoint never blocks deal creation.
API Contract
Request (VF → Operator)
POST {operator.endpoint_url}
Authorization: Bearer {operator.api_key}
Content-Type: application/json
X-VF-Signature: sha256={hmac_signature}
X-VF-Idempotency-Key: deal-{deal_id}-v1{
"vf_deal_id": 12345,
"streamer": {
"vf_username": "xQcOW",
"country": "CA"
},
"campaign": {
"vf_campaign_id": 88,
"name": "June Casino Push",
"category": "casino"
},
"terms": {
"deliveries": 5,
"timeframe_days": 30,
"payment_per_stream": 500.00
}
}The X-VF-Signature is an HMAC-SHA256 over the raw request body, keyed with the operator's shared secret. Operators should verify this before acting.
Response (Operator → VF)
{
"account_id": "player-xqcow-vf-001",
"login_url": "https://casino.example.com/login?token=abc123",
"balance_usd": 200.00,
"expires_at": "2026-05-03T00:00:00Z"
}All fields except login_url are optional. If the operator can only return a fast-track registration link (rather than a fully provisioned account), that is acceptable — VF surfaces whatever is returned.
Error response
{ "error": "Streamer country not supported", "code": "COUNTRY_RESTRICTED" }Any non-2xx response is logged against the provision record. VF retries up to 3 times with exponential backoff, then marks the provision as failed and surfaces a fallback message to the streamer.
Compliance Note
Regulated gambling operators cannot create real-money accounts without KYC in most jurisdictions. The contract is intentionally permissive — operators choose what they provision:
| Account type | Compliance path |
|---|---|
| Full real-money account | Requires streamer to have completed KYC at the operator |
| Pre-filled registration + bonus balance | Operator pre-registers; balance held until KYC completes on the operator's site |
| Fast-track registration link | Operator pre-fills form fields from VF data; streamer completes sign-up |
| Demo / practice account | No KYC required; lower value but immediately actionable |
VF does not dictate which type — the login_url and optional balance_usd are the only contract surface. Legal sign-off from at least one pilot operator is required before building.
Database Changes
-- Operator-side configuration (one row per operator that opts in)
CREATE TABLE operator_api_configs (
operator_id INTEGER PRIMARY KEY REFERENCES operators(id),
endpoint_url TEXT NOT NULL,
api_key_enc TEXT NOT NULL, -- AES-256 encrypted at rest; never returned by GET
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Per-deal provisioning result
CREATE TABLE deal_account_provisions (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
deal_id BIGINT NOT NULL REFERENCES deals(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending','success','failed')),
operator_account_id TEXT,
login_url TEXT,
balance_usd NUMERIC(18,6),
expires_at TIMESTAMPTZ,
raw_response JSONB,
attempted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
resolved_at TIMESTAMPTZ
);
CREATE UNIQUE INDEX ON deal_account_provisions (deal_id);API Changes
| Method | Endpoint | Description |
|---|---|---|
PUT | /api/operators/:slug/api-config | Operator saves/updates their endpoint URL and API key |
DELETE | /api/operators/:slug/api-config | Operator removes their integration |
GET | /api/deals/:id/account | Streamer retrieves their provisioned account for a deal |
POST | /api/admin/deals/:id/reprovision | Admin manually retriggers provisioning after failure |
The PUT endpoint accepts { endpoint_url, api_key } and stores the key encrypted. The key is write-only — it is never returned on GET.
Worker Job
A new job type provision_streamer_account is enqueued immediately after deal creation:
- Load
operator_api_configsfor the deal's operator — if none, no-op. - Build the request payload from the deal + offer + streamer rows.
- POST to
endpoint_urlwith HMAC signature and idempotency key. - Write result to
deal_account_provisions(successorfailed). - On
success: push a Pusher event toprivate-streamer-{streamer_id}so the deal page updates in real time. - On failure: retry up to 3× with exponential backoff (1 min, 5 min, 15 min), then mark
failed.
Frontend Changes
Operator portal — Settings
A new card in /operator/account:
┌─────────────────────────────────────────────────────────────┐
│ Account Provisioning API │
│ ────────────────────────────────────────────────────────── │
│ Automatically create a player account for streamers when │
│ a deal is signed. │
│ │
│ Endpoint URL [ https://casino.example.com/api/vf/... ] │
│ API Key [ •••••••••••••••• ] [ Rotate ] │
│ │
│ [ Save ] [ Remove integration ] │
└─────────────────────────────────────────────────────────────┘Streamer portal — Deal detail
A new card appears on the deal page once provisioning completes:
Pending state:
⏳ Setting up your account at Casino Royale…
This usually takes under a minute.Success state:
✅ Your account at Casino Royale is ready
─────────────────────────────────────
Balance: $200.00 USD
Expires: 3 May 2026
[ Open Casino Royale → ]Failed state:
ℹ️ Account setup unavailable
Please register directly at Casino Royale.
Support has been notified.Streamer Data Consent
The following streamer fields are sent to the operator:
vf_username— streamer's Verifluence usernamecountry— country from streamer profile
No email address, real name, or KYC data is sent. VF's Terms of Service must disclose that username and country are shared with the operator when a deal is created. An opt-out toggle is desirable for Phase 2 but is not a blocker for the pilot.
Account Lifecycle on Deal Cancellation
When a deal transitions to refunded or cancelled, VF will send a DELETE callback to the operator's endpoint (if configured):
DELETE {operator.endpoint_url}
Authorization: Bearer {operator.api_key}
X-VF-Signature: sha256={hmac_signature}
{ "vf_deal_id": 12345, "operator_account_id": "player-xqcow-vf-001" }Operators may revoke the account or reclaim the balance per their own policy. VF does not enforce what the operator does with this signal.
Implementation Phases
| Phase | Scope |
|---|---|
| Phase 1 — Pilot | Infrastructure + one pilot operator. Provision a fast-track registration link only. Validate end-to-end flow. |
| Phase 2 — GA | Open to all operators. Add full account provisioning and balance top-up for operators in permissive jurisdictions. |
| Phase 3 — Lifecycle | Cancellation callbacks, multi-campaign account reuse logic, balance reporting widget. |
Open Questions
| # | Question | Proposed default |
|---|---|---|
| OQ-1 | What account type can the pilot operator provision? | Confirm with operator before starting Phase 1 |
| OQ-2 | Should streamers be able to opt out of auto-provisioning? | Optional — MVP sends to all; opt-out in Phase 2 |
| OQ-3 | How is the API key encrypted at rest? | AES-256-GCM using a server-side key from environment |
| OQ-4 | Should the cancellation callback be synchronous with deal status change? | No — enqueue as a separate worker job |
| OQ-5 | What if the same streamer has two active deals with the same operator? | Operator's idempotency key includes deal_id, so they receive two separate provision requests |