ReferenceWidgets
Mystery Box widget
Once-a-day surprise reward — a weighted-random coin drop with a deterministic daily seed.
Mount
<script src="https://cdn.hatched.live/widget.js" data-session-token="SESSION_TOKEN" defer></script>
<div data-hatched-mount="mystery-box"></div>Opening the box is a write, so the Mystery Box widget must be mounted with a
session token. The state endpoint is readable with an embed token so the
widget can render its eligible / capped / locked face.
Script attributes
| Attribute | Values | Default |
|---|---|---|
data-session-token | widget session token | claim enabled |
data-embed-token | embed token | read-only state |
data-theme | light dark | light |
data-api-base-url | API origin + /api/v1 | https://api.hatched.live/api/v1 |
Required scopes
readrenders the box state.- Claiming requires a session token minted with the
mysterybox:claimscope; a session token withoutmysterybox:claimis rejected403, and embed tokens are read-only.
Plan & capability
- Capability:
mystery_box(tenant toggle in Settings → Capabilities). - Minimum plan: Growth.
- Two distinct 403s can come back on both
/stateand/claim— the capability is gated at the controller level, so the guard rejects before the handler runs:403 plan_feature_locked— the plan does not entitle the capability. Details carryrequired_planand anupgrade_url.403 capability_disabled— the plan entitles it but an operator turned the Settings toggle off for this workspace.
The { locked: true } state is the entitled-but-unavailable face, not the
not-entitled response: when the plan does not entitle mystery_box, both
/state and /claim return 403 plan_feature_locked before that branch runs.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /widget/mystery-box/state | locked / eligible / next_eligible_at / last reward |
POST | /widget/mystery-box/claim | Open the box — 409 mystery_box_daily_cap once spent |
The daily cap is one open per buddy and resets at midnight UTC. The reward draw
is deterministically seeded per (buddy, UTC day), so it can never be re-rolled.