Skip to content

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/entities

Request

FieldTypeRequiredDescription
entityTypestringYesEntity type as defined in your template (e.g. player, game)
externalIdstringYesYour unique identifier for this entity
dataobjectYesEntity 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

bash
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)

json
{
  "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/:externalId

Retrieves the entity with decrypted PII fields.

Example

bash
curl https://api.onehazel.com/operator-data-api/entities/player_12345 \
  -H "Authorization: Bearer oh_live_YOUR_API_KEY"

Response

json
{
  "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/:externalId

Performs 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

bash
curl -X DELETE https://api.onehazel.com/operator-data-api/entities/player_12345 \
  -H "Authorization: Bearer oh_live_YOUR_API_KEY"

Response

json
{
  "success": true,
  "message": "Entity deleted and data anonymized"
}

Error codes

HTTP StatusError CodeDescription
400MISSING_FIELDSentityType, externalId, or data is missing
400VALIDATION_FAILEDData does not match template requirements (details in error.details)
400TEMPLATE_NOT_CONFIGUREDNo template set — call PUT /settings first
401UNAUTHORIZEDMissing or invalid API key
404ENTITY_NOT_FOUNDNo entity with that externalId exists
429RATE_LIMITEDRate limit exceeded
500INTERNAL_ERRORServer error