# States States are key-value snapshots attached to entities. Unlike events (which are append-only), states represent the **current value** of something — a player's balance, KYC status, or risk score. Writing a state replaces the previous value for that key. ## Update a state ``` PUT /operator-data-api/entities/:externalId/state/:key ``` ### Path parameters | Parameter | Description | |---|---| | `externalId` | The entity's external ID | | `key` | The state key (must be defined in your template) | ### Request body The request body can be either: - An object with a `value` field: `{ "value": ... }` - The value directly as the body The value can be any JSON type — string, number, boolean, object, or array. ### Valid state keys (iGaming template) | Key | Typical value | Description | |---|---|---| | `balance` | `{ "amount": 145.50, "currency": "GBP" }` | Current wallet balance | | `kyc_status` | `"verified"` | KYC verification status | | `risk_score` | `"low"` | Responsible gaming risk assessment | | `loyalty_tier` | `"gold"` | Loyalty programme tier | ### Upsert semantics States use upsert on the composite key `(entity_id, state_key)`. If a state already exists for this entity and key, it is overwritten. If not, it is created. ### Example: Update balance ```bash curl -X PUT https://api.onehazel.com/operator-data-api/entities/player_12345/state/balance \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": { "amount": 145.50, "currency": "GBP", "last_updated": "2026-04-06T14:30:00Z" } }' ``` **Response:** ```json { "success": true, "data": { "stateKey": "balance", "value": { "amount": 145.50, "currency": "GBP", "last_updated": "2026-04-06T14:30:00Z" } } } ``` ### Example: Update KYC status ```bash curl -X PUT https://api.onehazel.com/operator-data-api/entities/player_12345/state/kyc_status \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "verified" }' ``` ### Example: Update risk score ```bash curl -X PUT https://api.onehazel.com/operator-data-api/entities/player_12345/state/risk_score \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "medium" }' ``` ## Get all states ``` GET /operator-data-api/entities/:externalId/state ``` Returns all current state snapshots for an entity. ### Example ```bash curl https://api.onehazel.com/operator-data-api/entities/player_12345/state \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` **Response:** ```json { "success": true, "data": [ { "state_key": "balance", "value": { "amount": 145.50, "currency": "GBP" }, "updated_at": "2026-04-06T14:30:00.000Z" }, { "state_key": "kyc_status", "value": "verified", "updated_at": "2026-04-06T11:00:00.000Z" }, { "state_key": "risk_score", "value": "medium", "updated_at": "2026-04-06T14:35:00.000Z" } ] } ``` ## Get a single state ``` GET /operator-data-api/entities/:externalId/state/:key ``` ### Example ```bash curl https://api.onehazel.com/operator-data-api/entities/player_12345/state/balance \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` **Response:** ```json { "success": true, "data": { "state_key": "balance", "value": { "amount": 145.50, "currency": "GBP" }, "updated_at": "2026-04-06T14:30:00.000Z" } } ``` ## Event fan-out When a state is updated, OneHazel emits an internal event of type `entity_state.updated.` (e.g. `entity_state.updated.kyc_status`). This can trigger workflows. ## Error codes | HTTP Status | Error Code | Description | |---|---|---| | `400` | `VALIDATION_FAILED` | Unknown state key — check your template's `state_keys` list | | `400` | `TEMPLATE_NOT_CONFIGURED` | No template set — call `PUT /settings` first | | `401` | `UNAUTHORIZED` | Missing or invalid API key | | `404` | `ENTITY_NOT_FOUND` | No entity with that `externalId` exists | | `404` | `NOT_FOUND` | State key does not exist for this entity (GET only) | | `429` | `RATE_LIMITED` | Rate limit exceeded | | `500` | `INTERNAL_ERROR` | Server error |