> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open-metadata.org/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenLineage Events

> Send single or batched OpenLineage RunEvents to create lineage in OpenMetadata.

# OpenLineage Events

Send OpenLineage `RunEvent` payloads to create lineage between the events' input and output datasets.

| Method | Endpoint | Body |
| - | - | - |
| `POST` | `/v1/openlineage/lineage` | One `RunEvent` object |
| `POST` | `/v1/openlineage/lineage/batch` | An object with an `events` array |

Paths in this reference are relative to the API base URL. For a server at `https://your-company.open-metadata.org`, the single-event URL is `https://your-company.open-metadata.org/api/v1/openlineage/lineage`.

## Prerequisites

Both endpoints require an OpenMetadata JWT in the `Authorization: Bearer` header and `EditLineage` permission on the `table` resource. The server's OpenLineage API must be enabled.

Automatic entity creation also requires `Create` permission for each missing table, database, or database schema that the event creates.

Datasets must resolve to existing catalog assets or satisfy the server's entity creation settings. Both `inputs` and `outputs` must contain at least one dataset to create an edge. By default, the server processes only `COMPLETE` events.

For more information, see [OpenLineage Compatibility](/v2.1.x-SNAPSHOT/how-to-guides/data-lineage/openlineage).

## Single Event Request

The following fields describe the `RunEvent` request body.

<ParamField body="eventTime" type="string" required>
  Time the event occurred, as an ISO 8601 timestamp in UTC.
</ParamField>

<ParamField body="producer" type="string" required>
  URI identifying the event producer.
</ParamField>

<ParamField body="schemaURL" type="string" required>
  URI identifying the OpenLineage event schema.
</ParamField>

<ParamField body="eventType" type="string">
  One of `START`, `RUNNING`, `COMPLETE`, `ABORT`, `FAIL`, or `OTHER`. Send `COMPLETE` for the default server filter. An omitted value is processed when the filter allows `COMPLETE`.
</ParamField>

<ParamField body="run" type="object" required>
  Contains the required `runId`, a UUID string, and optional run `facets`.
</ParamField>

<ParamField body="job" type="object" required>
  Contains the required `namespace` and `name` strings, and optional job `facets`.
</ParamField>

<ParamField body="inputs" type="array">
  Input datasets. Each dataset requires `namespace` and `name` strings. Dataset `facets` and `inputFacets` are optional.
</ParamField>

<ParamField body="outputs" type="array">
  Output datasets. Each dataset requires `namespace` and `name` strings. Dataset `facets` and `outputFacets` are optional.
</ParamField>

### Example RunEvent

Save the following payload as `event.json`. This example assumes the namespace maps to `prod-postgres` and both tables already exist with an `id` column. The output column maps to `prod-postgres.analytics.public.raw_orders.id`.

The response examples also assume that the pipeline `openlineage.orders-build_orders` exists. If the job has no matching pipeline, the server reports it in `unresolvedJobs` and can still create the dataset edges.

```json theme={null}
{
  "eventType": "COMPLETE",
  "eventTime": "2026-10-20T10:00:00Z",
  "producer": "https://example.com/lineage-producer",
  "schemaURL": "https://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/RunEvent",
  "run": {
    "runId": "2ad9b3d8-18cb-4e15-b48c-56362a50ea5c"
  },
  "job": {
    "namespace": "orders",
    "name": "build_orders",
    "facets": {
      "sql": {
        "_producer": "https://example.com/lineage-producer",
        "_schemaURL": "https://openlineage.io/spec/facets/1-0-0/SQLJobFacet.json#/$defs/SQLJobFacet",
        "query": "INSERT INTO analytics.public.orders SELECT id FROM analytics.public.raw_orders"
      }
    }
  },
  "inputs": [
    {
      "namespace": "postgresql://warehouse.example.com:5432",
      "name": "analytics.public.raw_orders"
    }
  ],
  "outputs": [
    {
      "namespace": "postgresql://warehouse.example.com:5432",
      "name": "analytics.public.orders",
      "facets": {
        "columnLineage": {
          "_producer": "https://example.com/lineage-producer",
          "_schemaURL": "https://openlineage.io/spec/facets/1-0-1/ColumnLineageDatasetFacet.json#/$defs/ColumnLineageDatasetFacet",
          "fields": {
            "id": {
              "inputFields": [
                {
                  "namespace": "postgresql://warehouse.example.com:5432",
                  "name": "analytics.public.raw_orders",
                  "field": "id"
                }
              ]
            }
          }
        }
      }
    }
  ]
}
```

Set the `OPENMETADATA_JWT` environment variable to your token, then send the saved event:

<RequestExample>
  ```bash theme={null}
  curl --request POST \
    "https://your-company.open-metadata.org/api/v1/openlineage/lineage" \
    --header "Authorization: Bearer $OPENMETADATA_JWT" \
    --header "Content-Type: application/json" \
    --data-binary @event.json
  ```
</RequestExample>

The following response indicates that the server wrote one lineage edge:

<ResponseExample>
  ```json theme={null}
  {
    "status": "success",
    "message": "Created 1 lineage edge(s)",
    "lineageEdgesCreated": 1,
    "unresolvedDatasets": [],
    "unresolvedJobs": []
  }
  ```
</ResponseExample>

## Batch Request

`POST /v1/openlineage/lineage/batch` accepts an object containing a required `events` array with at least one `RunEvent`. A bare JSON array is not a batch request.

Save this example as `batch.json`:

```json theme={null}
{
  "events": [
    {
      "eventType": "COMPLETE",
      "eventTime": "2026-10-20T10:00:00Z",
      "producer": "https://example.com/lineage-producer",
      "schemaURL": "https://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/RunEvent",
      "run": {
        "runId": "3aa06b9c-2185-4c64-959c-b549f768b251"
      },
      "job": {
        "namespace": "orders",
        "name": "build_orders"
      },
      "inputs": [
        {
          "namespace": "postgresql://warehouse.example.com:5432",
          "name": "analytics.public.raw_orders"
        }
      ],
      "outputs": [
        {
          "namespace": "postgresql://warehouse.example.com:5432",
          "name": "analytics.public.orders"
        }
      ]
    }
  ]
}
```

Send the batch to the batch endpoint:

```bash theme={null}
curl --request POST \
  "https://your-company.open-metadata.org/api/v1/openlineage/lineage/batch" \
  --header "Authorization: Bearer $OPENMETADATA_JWT" \
  --header "Content-Type: application/json" \
  --data-binary @batch.json
```

The following response represents one event that wrote one edge:

```json theme={null}
{
  "status": "success",
  "message": "Processed 1 events: 1 successful, 0 partial, 0 failed, 0 skipped. Created 1 lineage edges.",
  "summary": {
    "received": 1,
    "successful": 1,
    "failed": 0,
    "skipped": 0,
    "partial": 0
  },
  "lineageEdgesCreated": 1,
  "unresolvedDatasets": [],
  "unresolvedJobs": []
}
```

## Response Fields

Both endpoints return a JSON object. Batch responses also include processing counts.

| Field | Meaning |
| - | - |
| `status` | `success`, `partial_success`, or `failure`. |
| `message` | Human-readable processing result. |
| `lineageEdgesCreated` | Number of edge writes that succeeded. This is not a count of unique new relationships. |
| `summary.received` | Number of events in a batch. |
| `summary.successful` | Number of batch events with successful edge writes and no unresolved datasets. |
| `summary.partial` | Number of batch events that wrote edges but left some datasets unresolved. |
| `summary.failed` | Number of batch events that raised an exception or had unresolved datasets with no successful edge writes. |
| `summary.skipped` | Number of batch events with no successful edge writes and no unresolved datasets. |
| `failedEvents` | Batch failures, each with a zero-based `index`, a `reason`, and a `retriable` flag. The server sets `retriable` to `false`. |
| `unresolvedDatasets` | Datasets that could not be resolved or created. No edges touching these datasets were created. |
| `unresolvedJobs` | Jobs without a matching pipeline. Dataset edges can still be created without a pipeline reference. |

Each unresolved entry contains `namespace`, `name`, `reason`, and an explanatory `message`. Batch entries also contain a zero-based `eventIndex`. Reasons include `namespaceNotMapped`, `missingColumns`, `creationDisabled`, `createNotAllowed`, and `pipelineNotFound`.

A single event returns `partial_success` when it writes edges but leaves datasets unresolved. It returns `400` with `status: failure` when datasets are unresolved and no edge was written. A batch returns `400` when every event fails. Otherwise, it returns `200`, and its body reports the aggregate result.

A `200` response with `status: success` can still have `lineageEdgesCreated: 0` for a filtered event or an event without inputs or outputs. Individual edge-write failures are logged and do not necessarily produce a failed event. Check the counts and server logs, then verify the graph with [Get Lineage](/v2.1.x-SNAPSHOT/api-reference/lineage/get).

## HTTP Status Codes

Inspect the response body as well as the HTTP status.

| Code | Meaning |
| - | - |
| `200` | The server processed the request. The body describes the result. |
| `400` | The request format is invalid, a single event has unresolved datasets and no successful edge writes, or every batch event failed. |
| `401` | The authentication token is missing or invalid. |
| `403` | The caller lacks `EditLineage` permission on the `table` resource. |
| `500` | An unexpected exception prevented single-event processing. |
| `503` | The OpenLineage API is disabled in the server settings. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.