HatchedDocs
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

AttributeValuesDefault
data-session-tokenwidget session tokenclaim enabled
data-embed-tokenembed tokenread-only state
data-themelight darklight
data-api-base-urlAPI origin + /api/v1https://api.hatched.live/api/v1

Required scopes

  • read renders the box state.
  • Claiming requires a session token minted with the mysterybox:claim scope; a session token without mysterybox:claim is rejected 403, 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 /state and /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 carry required_plan and an upgrade_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

MethodPathPurpose
GET/widget/mystery-box/statelocked / eligible / next_eligible_at / last reward
POST/widget/mystery-box/claimOpen 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.