Appearance
Conformance
Before a module counts as conformant, OneHazel runs a fixed set of scenarios against the base URL you registered. Every wallet and player call is signed, carries X-OneHazel-Env: test, and uses only the test player you named; webhook deliveries are signed sha256= exactly as live ones are. A blocker failing keeps the module from going live; a major must be fixed before the first real vendor; a minor is advice.
Your coding agent can read the same list with connect_conformance_scenarios before writing any code. A run that has not finished is "not yet verified", never a pass. In connect_status, evidence: derived means no conformance run backs this module; in v1 that is launch, widget, attribution and events.push.
wallet
| Scenario | Severity | Passing looks like |
|---|---|---|
auth.bad_bearer | blocker | 401 with the error envelope; no wallet change |
auth.bad_signature | blocker | 401; the body is verified before it is parsed |
auth.stale_timestamp | blocker | 401 when the timestamp is more than 300 s off, even with a valid MAC |
balance.ok | blocker | 200 with an integer balance_minor and the player's currency |
bet.ok | blocker | 200, status: accepted, balance reduced by exactly amount_minor |
win.ok | blocker | 200, status: accepted, balance increased by exactly amount_minor |
bet.insufficient_funds | blocker | 402 insufficient_funds; the wallet is not touched |
bet.duplicate_returns_original | blocker | the ORIGINAL response with duplicate: true and no second debit |
rollback.bet | blocker | status: rolled_back, stake returned by your stored amount |
rollback.win | blocker | status: rolled_back, credit reversed by your stored amount |
rollback.amount_mismatch | major | rollback_amount_mismatch; nothing reversed |
freerounds.bet_no_debit | major | no wallet/bet for a free-round bet; balance unchanged until the win |
freerounds.settle_lump | major | freerounds/settle credits the lump itself, never alongside a wallet/win |
env.test_header_required | blocker | test traffic touches only the test player or sandbox ledger |
shape.empty_body_is_failure | blocker | every success matches the contract schema; a bare 2xx is a failure |
player
| Scenario | Severity | Passing looks like |
|---|---|---|
lookup.ok | blocker | 200 with player_external_id, currency, country, status and a restrictions array |
lookup.unknown_404 | major | 404 with the error envelope, never a 200 with empty fields |
lookup.restricted_flag | major | restrictions lists the active restriction; empty only when none |
webhook.receive
| Scenario | Severity | Passing looks like |
|---|---|---|
deliver.ok | blocker | 2xx after verifying X-OneHazel-Signature: sha256=<hex> over the raw body (no timestamp, no bearer, no env header) |
deliver.replay_ignored | major | 2xx both times for the same deliveryId, processed once |
deliver.tampered_rejected | blocker | non-2xx for a body altered after signing |
deliver.timeout_5s | major | the 2xx arrives within 5 s; slow work runs after acknowledging |
Check it yourself first
The generated samples are built to these scenarios. To exercise your own build before asking OneHazel to run, sign requests with signForTest from @onehazel/connect and replay the table above against your local server.
See also
- Per-module guides: wallet, player, webhook.receive.
- Troubleshooting for failed scenarios and errored runs.