Quick start

The book is one iframe. There is no SDK, no build step and nothing to install on your server.

<iframe src="https://iframe.winhouse.bet/book?key=ifr_your_key&embed=1" style="width:100%;height:900px;border:0" allow="fullscreen"></iframe>

Three things have to be true before it will render on your site:

  1. Your key is active (see the dashboard).
  2. Your domain is on the allow-list — see Domains.
  3. Your own Content-Security-Policy permits our origin — see CSP.

The embed key

Your key looks like ifr_ followed by 40 hex characters. It identifies which brand's skin to paint and nothing else.

The key is not a secret. It sits in your page source where anyone can read it, so it is public by construction. It grants no access to data and no ability to place bets. What stops another site embedding your book is the domain allow-list, not the key.

Rotating the key from the dashboard invalidates the old one immediately, so update your page in the same change.

Domains & going live

A new account is in sandbox: the book works and you can preview it, but it refuses to load inside any site until you add a domain.

Add exact origins, one per line — scheme, host and port must match:

https://example.com https://www.example.com https://staging.example.com

Wildcards are deliberately not supported. *.example.com would mean an abandoned or hijacked subdomain becomes a valid host for your book.

We derive a frame-ancestors policy from that list:

GET /tenant/frame-policy?key=ifr_... { "header": "frame-ancestors 'self' https://example.com" }

With no domains configured it resolves to frame-ancestors 'none' — the book fails closed rather than being embeddable anywhere.

Sizing the frame

The book scrolls internally. Give it a real height — a sportsbook inside a short box becomes a scroll within a scroll and is unusable on a phone.

.sportsbook iframe { display: block; width: 100%; height: calc(100dvh - 70px); /* viewport minus your header */ min-height: 560px; border: 0; } @media (max-width: 760px) { .sportsbook iframe { height: calc(100dvh - 132px); } /* header + your bottom nav */ }

Watch a fixed bottom nav. The book puts its own tab bar at the bottom of the frame on phones. If your site has a fixed bottom navigation, subtract its height too or the two overlap and neither is tappable.

If your page wrapper constrains width or adds a top margin, break out of it:

.sportsbook { margin-top: 0; width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); }

Your site's CSP

Allow-listing your domain with us is necessary but not sufficient. If your site sends a Content-Security-Policy, its frame-src must also name our origin, or the browser blocks the frame before it loads.

Content-Security-Policy: frame-src 'self' https://iframe.winhouse.bet;

The symptom is a console message and an empty frame:

Refused to frame 'https://iframe.winhouse.bet/' because it violates the following Content Security Policy directive: "frame-src 'self' ..."

URL parameters

ParameterMeaning
keyRequired. Your embed key.
embed=1Skip the book's own top bar and left rail. Use this when your page already has a header, or the chrome is doubled.
preview_themeURL-encoded JSON of token overrides, for previewing a skin before saving. Styling only.

Theme tokens

The book is built on CSS custom properties. Your skin is a set of overrides for them, served with the book and applied to :root at boot. Set one from the dashboard and everything using it repaints — there is no per-page styling to chase.

GET /tenant/config?key=ifr_... { "ok": true, "name": "Acme Bet", "theme": { "accent": "#FF8A00", "bg": "#12100E", "radius": "14px" } }

Values are validated on both sides: a token must be a hex colour or a short length (px, rem, em, %). Anything else — url(...), a closing brace, a whole rule — is dropped rather than escaped, because these values land in a stylesheet.

Token reference

Blank inherits the default. Thirty-one tokens across six groups.

GroupTokens
Brandaccent accent-ink brand green blue
Surfacesbg surface surface-2 surface-3 hover border track disabled
Shellshell shell-line nav-txt nav-sub
Texttext text-2 text-dim text-faint
Statuslive up down win-green hl-pink
Layoutradius row-h odd-w sidebar-w slip-w

up and down are the price-movement flashes; live is the in-play badge; odd-w and row-h control the density of the board.

Account models

There are two ways to run players, and the choice decides how money moves. Pick one before you launch — switching later means migrating balances.

A. Book-side accounts

Players register and sign in inside the book. They sit in your own agent tree, and bets settle against the balance you fund from your operator credit line. Nothing is required from your site: embed the iframe and you are done.

B. Seamless wallet

Your site stays the source of truth for both identity and money. Your existing players sign in on your site, and the book debits and credits your wallet for every bet and settlement. This needs endpoints on your side — see below.

Being signed in on your site does not sign a player into the book on its own. They are separate systems with separate databases, and a third-party iframe cannot read your session. Model B is what connects them.

Seamless wallet (model B)

Two endpoints on your side, called server-to-server. Authenticate with a shared callback token and sign the payload; never trust the browser for either.

Player lookup

GET /api/integrations/winhouse/user-data?token=<callback>&username=player_123 → { "username": "player_123", "balance": "250.00", "currency": "EUR" }

Balance change

POST /api/integrations/winhouse/balance-change?token=<callback> { "username": "player_123", "transaction_id": "wh_9f2c…", // idempotency key "amount": -25.00, // negative = bet, positive = win "signature": "<hmac-sha256 of the payload>" } → { "status": "ok", "balance": "225.00" }

Rules your endpoint must follow

Retries happen. Treat every write as "may arrive twice, possibly out of order" — the idempotency key is what makes that safe.

Agent panel

Your network lives at winhouse.bet/agent/ with the boss account issued when your customer was created: managers, agents, shops and players, credit down the chain, stake limits, market blocks, tickets, settlement and reports.

Your tree is scoped to you. No other operator can see it, and you cannot see theirs.

Suspension

Suspending an account disables the embed and the boss login together, and takes effect immediately — the config endpoint is intentionally uncached, so a suspension is a real kill switch rather than something that expires later.

A suspended key returns 404 from /tenant/config and the book will not render.

Troubleshooting

SymptomCause
Empty frame, console says "Refused to frame" Your site's CSP frame-src does not list our origin.
Frame loads but shows nothing / refuses Your domain is not on the allow-list, or the account is still in sandbox.
Book asks players to log in although they are signed in on your site Expected without model B. The two systems are separate.
Colours did not change A token failed validation and was dropped — it must be a hex colour or a short length.
Chrome appears twice (two headers) Add &embed=1 to the iframe URL.
Bottom tab bar unreachable on mobile Your fixed bottom nav overlaps the frame — subtract its height from the iframe height.
Old snippet stopped working The key was rotated. Copy the current one from the dashboard.

Something not covered here? sales@winhouse.bet.