Campaign studio
Design, preview and export a self-hosted wheel, scratch card or mystery box. Local demos or merchant API results; no hosted prize service.
- Component: Lucky wheel / Scratch card / Mystery boxes
- Theme: Coastal minimal / Candy pop / Retro arcade / Midnight gold / Festival paper / Garden sketch
Result source
Local draws are editable demonstrations, not secure prize allocation. Public offers in exported code are visible to visitors. No stock, identity or repeat-entry protection is provided.
Your server owns authentication, odds, inventory, eligibility and idempotency. Never put secret keys in this editor. Preview never calls your endpoint.
Merchant API integration guide
This is an interface contract, not an Elysia draw service. Implement POST /api/draw on your server, set the same campaign ID and prize IDs there, then enter that endpoint here. Download and host the files on HTTPS to test real draws; the editor only simulates them.
Request · POST application/json
The widget sends only version, campaignId and a random 32-character hexadecimal requestId. It sends no customer ID, probabilities or API key. The server must identify the participant independently; requestId is not a login credential.
{
"version": 1,
"campaignId": "summer-boutique",
"requestId": "0123456789abcdef0123456789abcdef"
}
Success · 200 application/json
Echo requestId exactly. prizeId must match a configured prize, including a no-prize entry. Optional: receiptId (≤200 characters), claim.code (≤300), claim.url (HTTPS, ≤2048). Omit unused fields instead of sending null. The response has no data/result wrapper and must be ≤16 KiB. A failed draw is not a no-prize result.
{
"requestId": "0123456789abcdef0123456789abcdef",
"prizeId": "p1",
"receiptId": "draw_2026_001",
"claim": {
"code": "SAMPLE-ONLY",
"url": "https://shop.example/redeem"
}
}
Configured prize IDs:
p1: 10% off
p2: Free shipping
p3: Mystery gift
p4: Maybe next time
Prefer hosting the widget and /api/draw on the same origin (scheme + host + port), using a server-side reverse proxy if needed. Relative paths resolve against the widget page, not the parent shop page. fetch uses credentials: same-origin; only same-origin cookies are sent. No Authorization header or custom headers are configurable. Cross-origin endpoints need CORS for the widget origin and OPTIONS for POST + Content-Type; cross-origin cookies are not sent. A static HTML file alone cannot implement authenticated draws. Third-party iframe cookie restrictions can still affect sessions.
The backend must authenticate participants, validate Origin/CSRF and campaign eligibility, enforce entry limits and rate limits, choose prizes using server-owned odds, and reserve stock and save the outcome in one transaction. Persist idempotency by participant + campaignId + requestId, returning the same outcome on retries. Enforce redemption and expiry server-side. Never trust browser odds, IDs or claim codes as proof of entitlement; never put secrets in this editor or exports.
Reject requests with an appropriate non-2xx status (for example 401/403/409/429/503). The widget shows a generic unconfirmed-result message, not the server error text. It times out after 15 seconds and rejects redirects, invalid JSON, mismatched requestId, unknown prizes and unsafe claim URLs. Manual retry reuses the pending ID only on this page; reloading creates a new ID, so entry limits must be persistent. There is no automatic retry or local-prize fallback.
Offline appearance preview stays live while API or hosting fields are incomplete. Complete the highlighted fields to export; invalid prize or style fields keep the last valid preview.
Export and embed
HTML / CSS / JavaScript / JSON. Host the exported files on your HTTPS site, then paste that page URL here. This tool does not publish or host campaigns.
Optional images load from their HTTPS hosts in visitors’ browsers. No images or API keys are stored by this editor.
Equal-size sectors are visual only; listed probabilities determine local demo results. In API mode, the server decides.