POST 1 to 1,000 typed OpenLineage events in one bounded delivery.
POST /api/v1/lineage/batchAccepts 1 to 1,000 RunEvent, JobEvent, or DatasetEvent objects defined by the OpenLineage object model and OpenLineage 2-0-2 JSON schema.
The query parameters and authorization match the single-event route. The body is an OpenLineageBatchRequest: either an event array or an object with an events array.
Send Authorization: Bearer <token>. The token needs write scope and the caller needs the editor workspace role or higher. See authentication.
Idempotency-Key is optional and accepts 1 to 600 characters. Reuse a key only for the exact same request bytes. A reused key with different bytes returns 409 lineage_idempotency_conflict; without a key, byte-identical batches deduplicate by SHA-256 digest.
| Name | Type | Required | Description |
|---|---|---|---|
workspace_id | string | With session JWTs or other unscoped tokens | Target workspace. A workspace-scoped PAT can omit it; an explicit value must match the token's workspace. |
connector_id | string | No | Connector scope used to resolve dataset identities. |
provider_key | string, 1–500 characters | No | Stable producer identity with an immutable connector binding. |
| Name or limit | Value |
|---|---|
Authorization | Required bearer token with write scope. |
Content-Type | Required; application/json. |
Idempotency-Key | Optional; 1–600 characters. |
| Request size | At most 8 MiB, uncompressed. |
| Logical events | 1–1,000. |
Send either an array of events or { "events": [...] }. Each object uses the same typed contract as single-event ingestion. Non-object children are durably quarantined and counted in invalid_item_count; semantic validation of object children continues asynchronously.
{
"events": [
{
"eventType": "COMPLETE",
"eventTime": "2026-08-05T18:42:12Z",
"producer": "https://github.com/acme/orders-pipeline",
"schemaURL": "https://openlineage.io/spec/2-0-2/OpenLineage.json",
"run": {
"runId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
},
"job": {
"namespace": "airflow-production",
"name": "orders.refresh_orders"
},
"inputs": [
{
"namespace": "snowflake://acme.us-east-1",
"name": "RAW.PUBLIC.ORDERS"
}
],
"outputs": [
{
"namespace": "snowflake://acme.us-east-1",
"name": "ANALYTICS.PUBLIC.ORDERS"
}
]
}
]
}curl --request POST \
--url "https://api.embrasure.ai/api/v1/lineage/batch?workspace_id=workspace-1&connector_id=connector-1&provider_key=airflow-production" \
--header "Authorization: Bearer $EMBRASURE_API_TOKEN" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: airflow-batch-842" \
--data-binary @openlineage-events.json202 response{
"delivery_id": "f68b6d87-7ad0-47ea-bc6a-af249f35ef1b",
"state": "accepted",
"duplicate": false,
"item_count": 42,
"invalid_item_count": 0
}item_count includes every child. invalid_item_count reports children that were not JSON objects and were quarantined during transport inspection.
All failures use the shared error envelope.
| Status | Codes | When |
|---|---|---|
400 | openlineage_body_required, openlineage_invalid_json, openlineage_invalid_batch, invalid_content_length | Missing/malformed JSON, unsupported envelope shape, empty array, duplicate keys, or invalid length header. |
401 | unauthorized | Missing or invalid bearer token. |
403 | insufficient_scope, insufficient_workspace_role, workspace_token_mismatch | Token or caller cannot write to the workspace. |
409 | lineage_idempotency_conflict, lineage_provider_scope_conflict | A retry key has different bytes, or the provider/connector binding conflicts. |
413 | openlineage_body_too_large, openlineage_batch_too_large | Body exceeds 8 MiB or contains more than 1,000 events. |
415 | openlineage_content_encoding_unsupported | Request body is compressed. |
422 | openlineage_workspace_required, validation_error | Workspace cannot be inferred or a query/header constraint fails. |
The LineageDeliveryReceipt confirms durable acceptance; semantic validation and graph projection continue asynchronously. |