Entities
Entities are the core records in OneHazel. A player, a game, an operator account — each is represented as an entity with a type, an external ID, and a data payload.
Create or update an entity
POST /operator-data-api/entitiesRequest
| Field | Type | Required | Description |
|---|---|---|---|
entityType | string | Yes | Entity type as defined in your template (e.g. player, game) |
externalId | string | Yes | Your unique identifier for this entity |
data | object | Yes | Entity data — must include all required fields from the template |
Upsert semantics
If an entity with the same externalId already exists for your operator, the data is updated and the entity type is set to the provided value. If it does not exist, a new entity is created.
PII encryption
Fields listed as PII in your template's pii_fields configuration are automatically encrypted before storage using AES-256-GCM with a per-operator derived key. For the iGaming template, PII fields for the player entity type typically include first_name, last_name, email, phone, and date_of_birth.
PII is decrypted only when reading a single entity via GET /entities/:externalId — it remains encrypted in bulk queries.
Idempotency
You can include an Idempotency-Key header to prevent duplicate processing. If a request with the same idempotency key has already been processed, the original response is returned. Keys expire after 24 hours.
Example
curl -X POST https://api.onehazel.com/operator-data-api/entities \
-H "Authorization: Bearer oh_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-player-12345" \
-d '{
"entityType": "player",
"externalId": "player_12345",
"data": {
"first_name": "James",
"last_name": "Wilson",
"email": "james.wilson@example.com",
"country": "GB",
"currency": "GBP",
"date_of_birth": "1992-03-15",
"registration_date": "2026-04-06T10:30:00Z",
"status": "active",
"vip_level": "bronze"
}
}'Response (201 Created)
{
"success": true,
"data": {
"id": "ent_a1b2c3d4e5f67890",
"externalId": "player_12345",
"entityType": "player",
"action": "created"
}
}If the entity already exists, the response status is 200 and action is "updated".
Get an entity
GET /operator-data-api/entities/:externalIdRetrieves the entity with decrypted PII fields.
Example
curl https://api.onehazel.com/operator-data-api/entities/player_12345 \
-H "Authorization: Bearer oh_live_YOUR_API_KEY"Response
{
"success": true,
"data": {
"id": "ent_a1b2c3d4e5f67890",
"external_id": "player_12345",
"entity_type": "player",
"data": {
"first_name": "James",
"last_name": "Wilson",
"email": "james.wilson@example.com",
"country": "GB",
"currency": "GBP",
"date_of_birth": "1992-03-15",
"registration_date": "2026-04-06T10:30:00Z",
"status": "active",
"vip_level": "bronze"
},
"created_at": "2026-04-06T10:30:00.000Z",
"updated_at": "2026-04-06T10:30:00.000Z"
}
}Delete an entity (GDPR)
DELETE /operator-data-api/entities/:externalIdPerforms a soft delete: entity data is replaced with a deletion marker, related events are redacted, and states are removed. This supports GDPR right-to-erasure requests.
Example
curl -X DELETE https://api.onehazel.com/operator-data-api/entities/player_12345 \
-H "Authorization: Bearer oh_live_YOUR_API_KEY"Response
{
"success": true,
"message": "Entity deleted and data anonymized"
}Error codes
| HTTP Status | Error Code | Description |
|---|---|---|
400 | MISSING_FIELDS | entityType, externalId, or data is missing |
400 | VALIDATION_FAILED | Data does not match template requirements (details in error.details) |
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 |
429 | RATE_LIMITED | Rate limit exceeded |
500 | INTERNAL_ERROR | Server error |