Skip to content
arch v1.0.0

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)

http
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
json
{
  "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)

json
{
  "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

json
{ "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 typeCompliance path
Full real-money accountRequires streamer to have completed KYC at the operator
Pre-filled registration + bonus balanceOperator pre-registers; balance held until KYC completes on the operator's site
Fast-track registration linkOperator pre-fills form fields from VF data; streamer completes sign-up
Demo / practice accountNo 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

sql
-- 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

MethodEndpointDescription
PUT/api/operators/:slug/api-configOperator saves/updates their endpoint URL and API key
DELETE/api/operators/:slug/api-configOperator removes their integration
GET/api/deals/:id/accountStreamer retrieves their provisioned account for a deal
POST/api/admin/deals/:id/reprovisionAdmin 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:

  1. Load operator_api_configs for the deal's operator — if none, no-op.
  2. Build the request payload from the deal + offer + streamer rows.
  3. POST to endpoint_url with HMAC signature and idempotency key.
  4. Write result to deal_account_provisions (success or failed).
  5. On success: push a Pusher event to private-streamer-{streamer_id} so the deal page updates in real time.
  6. 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.

The following streamer fields are sent to the operator:

  • vf_username — streamer's Verifluence username
  • country — 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):

http
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

PhaseScope
Phase 1 — PilotInfrastructure + one pilot operator. Provision a fast-track registration link only. Validate end-to-end flow.
Phase 2 — GAOpen to all operators. Add full account provisioning and balance top-up for operators in permissive jurisdictions.
Phase 3 — LifecycleCancellation callbacks, multi-campaign account reuse logic, balance reporting widget.

Open Questions

#QuestionProposed default
OQ-1What account type can the pilot operator provision?Confirm with operator before starting Phase 1
OQ-2Should streamers be able to opt out of auto-provisioning?Optional — MVP sends to all; opt-out in Phase 2
OQ-3How is the API key encrypted at rest?AES-256-GCM using a server-side key from environment
OQ-4Should the cancellation callback be synchronous with deal status change?No — enqueue as a separate worker job
OQ-5What 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

Verifluence Documentation