# Data Ingestion OneHazel's data ingestion API lets you push structured data from your platform into OneHazel, where it flows through workflows, analytics, and supplier integrations. ## Data model OneHazel uses three complementary data structures: ### Entities An **entity** is a record that represents a thing in your system — a player, a game, a wallet. Entities are identified by a unique `externalId` that you control (e.g. your internal player ID). Sending the same `externalId` twice updates the existing entity rather than creating a duplicate. ### Events An **event** is an immutable log entry attached to an entity. Events represent things that happened — a deposit, a game round, a login. Events are append-only: once recorded, they cannot be modified or deleted. ### States A **state** is a key-value snapshot attached to an entity. States represent the current value of something — the player's balance, their KYC status, their loyalty tier. Writing a state overwrites the previous value for that key. ## How they relate ``` Entity (player_12345) ├── Events (append-only log) │ ├── transaction: deposit £50 │ ├── game_activity: bet £5 on roulette │ └── session: logged in from GB └── States (latest snapshots) ├── balance: £45.00 ├── kyc_status: verified └── risk_score: low ``` ## Template system Before sending data, you must configure a **data template** that defines the valid entity types, event types, and state keys for your integration. Templates also define which fields contain PII and should be encrypted. OneHazel provides a built-in `tpl_igaming` template for iGaming operators. Set it up with: ```bash curl -X PUT https://api.onehazel.com/operator-data-api/settings \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "templateId": "tpl_igaming" }' ``` ### iGaming template structure **Entity types:** `player`, `operator`, `game` **Event types:** | Event Type | Description | Required Fields | |---|---|---| | `transaction` | Deposits, withdrawals, adjustments | `type`, `amount`, `currency` | | `game_activity` | Bets, wins, game rounds | `game_id`, `bet_amount` | | `session` | Logins, logouts, session tracking | — | | `bonus` | Bonus awards, wagering progress | — | | `block` | Self-exclusion, account restrictions | — | | `support` | Support tickets, interactions | — | | `affiliate` | Affiliate tracking, attribution | — | **State keys:** `balance`, `kyc_status`, `risk_score`, `loyalty_tier` ### Validation All data sent to OneHazel is validated against your configured template: - Unknown entity types are rejected - Unknown event types are rejected - Unknown state keys are rejected - Missing required fields are flagged in the response ### Listing templates ```bash curl https://api.onehazel.com/operator-data-api/templates \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` ## PII encryption Fields designated as PII in the template schema are **automatically encrypted** when data is ingested. Encryption uses AES-256-GCM with HKDF per-operator key derivation, so each operator's data is encrypted with a unique derived key. PII fields are only decrypted when reading a single entity — they remain encrypted in bulk queries and analytics aggregations. This means analytics can count and aggregate without ever exposing personal data. ## Base URL All data ingestion endpoints are under: ``` https://api.onehazel.com/operator-data-api ``` ## Endpoints | Method | Path | Description | |---|---|---| | `GET` | `/templates` | List available templates | | `GET` | `/settings` | Get your template and retention config | | `PUT` | `/settings` | Set your template and retention config | | `POST` | `/entities` | Create or update an entity | | `GET` | `/entities/:externalId` | Get an entity | | `DELETE` | `/entities/:externalId` | Soft-delete an entity (GDPR) | | `POST` | `/entities/:externalId/events` | Record an event | | `GET` | `/entities/:externalId/events` | List entity events | | `PUT` | `/entities/:externalId/state/:key` | Update a state | | `GET` | `/entities/:externalId/state` | Get all states | | `GET` | `/entities/:externalId/state/:key` | Get a single state | | `POST` | `/batch/entities` | Bulk upsert entities (max 1000) | | `POST` | `/batch/events` | Bulk insert events (max 5000) | | `POST` | `/batch/states` | Bulk upsert states (max 1000) | | `GET` | `/batch/jobs/:jobId` | Check batch job status | ## Next steps - [Entities](/data-ingestion/entities) — Creating and updating entities - [Events](/data-ingestion/events) — Recording events - [States](/data-ingestion/states) — Managing state snapshots - [Batch operations](/data-ingestion/batch) — Bulk data loading