# Batch Operations Batch endpoints let you send large volumes of data in a single request. Use them for initial data loads, migrations, or periodic bulk syncs. ## Batch entities ``` POST /operator-data-api/batch/entities ``` Upserts up to **1,000 entities** in a single request. Each entity follows the same format as the individual `POST /entities` endpoint. ### Request body An array of entity objects: ```json [ { "entityType": "player", "externalId": "player_001", "data": { ... } }, { "entityType": "player", "externalId": "player_002", "data": { ... } } ] ``` ### Example ```bash curl -X POST https://api.onehazel.com/operator-data-api/batch/entities \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "entityType": "player", "externalId": "player_001", "data": { "first_name": "Alice", "last_name": "Chen", "email": "alice@example.com", "country": "GB", "currency": "GBP", "status": "active" } }, { "entityType": "player", "externalId": "player_002", "data": { "first_name": "Bob", "last_name": "Smith", "email": "bob@example.com", "country": "MT", "currency": "EUR", "status": "active" } } ]' ``` ### Response ```json { "success": true, "data": { "jobId": "job_d4e5f6789012abcd", "succeeded": 2, "failed": 0, "errors": [] } } ``` ### Partial failures If some entities fail validation, the response includes details for each failure: ```json { "success": true, "data": { "jobId": "job_d4e5f6789012abcd", "succeeded": 1, "failed": 1, "errors": [ { "index": 1, "externalId": "player_002", "code": "VALIDATION_FAILED", "message": "Missing required field: \"email\"" } ] } } ``` ## Batch events ``` POST /operator-data-api/batch/events ``` Inserts up to **5,000 events** in a single request. Each event must reference an existing entity by `externalId`. ### Request body An array of event objects: ```json [ { "externalId": "player_001", "eventType": "transaction", "data": { ... } }, { "externalId": "player_001", "eventType": "game_activity", "data": { ... } } ] ``` ### Example ```bash curl -X POST https://api.onehazel.com/operator-data-api/batch/events \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "externalId": "player_001", "eventType": "transaction", "data": { "type": "deposit", "amount": 100.00, "currency": "GBP", "method": "bank_transfer" } }, { "externalId": "player_001", "eventType": "game_activity", "data": { "game_id": "european-roulette", "bet_amount": 10.00, "win_amount": 25.00, "currency": "GBP" } }, { "externalId": "player_002", "eventType": "transaction", "data": { "type": "deposit", "amount": 50.00, "currency": "EUR", "method": "card" } } ]' ``` ### Response ```json { "success": true, "data": { "succeeded": 3, "failed": 0, "errors": [] } } ``` ## Batch states ``` POST /operator-data-api/batch/states ``` Upserts up to **1,000 state snapshots** in a single request. ### Request body An array of state objects: ```json [ { "externalId": "player_001", "stateKey": "balance", "value": { ... } }, { "externalId": "player_001", "stateKey": "kyc_status", "value": "verified" } ] ``` ### Example ```bash curl -X POST https://api.onehazel.com/operator-data-api/batch/states \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "externalId": "player_001", "stateKey": "balance", "value": { "amount": 250.00, "currency": "GBP" } }, { "externalId": "player_001", "stateKey": "kyc_status", "value": "verified" }, { "externalId": "player_002", "stateKey": "balance", "value": { "amount": 50.00, "currency": "EUR" } }, { "externalId": "player_002", "stateKey": "loyalty_tier", "value": "silver" } ]' ``` ### Response ```json { "success": true, "data": { "succeeded": 4, "failed": 0, "errors": [] } } ``` ## Checking job status Batch entity operations create a job record that you can poll: ``` GET /operator-data-api/batch/jobs/:jobId ``` ### Example ```bash curl https://api.onehazel.com/operator-data-api/batch/jobs/job_d4e5f6789012abcd \ -H "Authorization: Bearer oh_live_YOUR_API_KEY" ``` ### Response ```json { "success": true, "data": { "id": "job_d4e5f6789012abcd", "type": "batch_ingest_entities", "status": "completed", "progress": 100, "output": { "succeeded": 2, "failed": 0, "errors": [] }, "error": null, "created_at": "2026-04-06T12:00:00.000Z", "completed_at": "2026-04-06T12:00:01.500Z" } } ``` ## Limits | Endpoint | Maximum items per request | |---|---| | `POST /batch/entities` | 1,000 | | `POST /batch/events` | 5,000 | | `POST /batch/states` | 1,000 | ## Synchronous vs asynchronous Batch entity operations create a job queue entry for tracking, but currently process inline (synchronously). The response includes the full result immediately. For initial data seeding where you need guaranteed ordering (e.g. create entities before recording events against them), use the individual `POST /entities` endpoint in sequence rather than the batch endpoint. ## Error codes | HTTP Status | Error Code | Description | |---|---|---| | `400` | `INVALID_INPUT` | Body is not a non-empty array, or exceeds the maximum batch size | | `400` | `TEMPLATE_NOT_CONFIGURED` | No template set — call `PUT /settings` first | | `401` | `UNAUTHORIZED` | Missing or invalid API key | | `404` | `NOT_FOUND` | Job ID not found (for status check) | | `429` | `RATE_LIMITED` | Rate limit exceeded for `ingest:batch` | | `500` | `INTERNAL_ERROR` | Server error |