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

# Create ingestion job

> Starts a historical data ingestion job.

```python theme={null}
olira.create_ingestion_job(
    file: str | None = None,
    records: list[IngestRecord] | None = None,
    idempotency_key: str | None = None,
    require_confirmation: bool = True,
    rollback_on_cancel: bool = False,
    summary_types: list[str] | None = None,
    max_event_logs: int | None = None,
) -> IngestionJob
```

**Requires scope:** `sdk:historical-ingest`

Provide either file= (JSONL path — SDK uploads to S3 then creates the job) or records= (inline list, ≤ 50,000 rows). Local validation runs before any network call. Phase 1 runs automatically; by default the job pauses at awaiting\_confirmation for review before graph replay.

## Parameters

<ParamField body="file" type="str | None">
  Path to a JSONL file (patient and/or log rows). Max size from org SDK config (default 100 MB).
</ParamField>

<ParamField body="records" type="list[IngestRecord] | None">
  Inline records when file= is not used. One of file or records is required.
</ParamField>

<ParamField body="idempotency_key" type="str | None">
  Stable job key; prevents duplicate active/completed jobs (409). Reusable after FAILED.
</ParamField>

<ParamField body="require_confirmation" type="bool" default="True">
  When True (default), pause at awaiting\_confirmation before Phase 2 replay.
</ParamField>

<ParamField body="rollback_on_cancel" type="bool" default="False">
  When True, delete patients created by this job on cancel. STALE logs are always deleted on cancel.
</ParamField>

<ParamField body="summary_types" type="list[str] | None">
  View summary\_type identifiers to backfill in Phase 2; None = all active org templates.
</ParamField>

<ParamField body="max_event_logs" type="int | None">
  Per-patient cap on logs considered during view backfill only (cost control for log-dense patients).
</ParamField>

## Returns

`IngestionJob` — Job snapshot including job\_id, status, stage, and progress counters.

<ResponseField name="job_id" type="str">
  Job identifier for polling and confirm/cancel.
</ResponseField>

<ResponseField name="status" type="str">
  e.g. queued, awaiting\_confirmation, replaying, completed.
</ResponseField>

<ResponseField name="stage" type="str">
  Human-readable pipeline stage.
</ResponseField>

<ResponseField name="progress_pct" type="float">
  0–100 progress estimate.
</ResponseField>

<ResponseField name="patients_processed" type="int">
  Patients inserted or updated in Phase 1.
</ResponseField>

<ResponseField name="logs_processed" type="int">
  Logs successfully inserted as STALE rows.
</ResponseField>

<ResponseField name="logs_failed" type="int">
  Logs rejected during validation/insert.
</ResponseField>

<ResponseField name="error_summary" type="list[IngestionErrorSummary] | None">
  Up to 100 sample errors (line, code, message).
</ResponseField>

## Raises

| Exception         | When                                                                                                                  |
| ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| `ValidationError` | Client-side JSONL/records validation failed, or file exceeds size limit — no job created.                             |
| `AuthError`       | HTTP 401 or 403 — invalid API key or insufficient OAuth scope for this endpoint.                                      |
| `ServerError`     | HTTP 409 (e.g. conflicting external identifier) or repeated 5xx after retries; includes status\_code when applicable. |
| `RateLimitError`  | HTTP 429 — rate limited; check retry\_after (seconds).                                                                |
| `NetworkError`    | Connection timeout, DNS failure, or read error after retries.                                                         |

<RequestExample>
  ```python Python theme={null}
  import olira

  olira.init(api_key="YOUR_API_KEY")
  job = olira.create_ingestion_job(
      file="patients_and_logs.jsonl",
      idempotency_key="initial-onboarding-2026",
      require_confirmation=True,
  )
  ```

  ```http HTTP theme={null}
  POST /v1/ingestion/jobs
  Authorization: Bearer YOUR_API_KEY
  Content-Type: application/json

  {
    "s3_key": "…",
    "idempotency_key": "initial-onboarding-2026",
    "require_confirmation": true
  }
  ```
</RequestExample>

<ResponseExample>
  ```python 200 theme={null}
  IngestionJob(
      job_id="ing-job-001",
      status="awaiting_confirmation",
      stage="awaiting_confirmation",
      progress_pct=100.0,
      patients_processed=42,
      logs_processed=1250,
      logs_failed=3,
      error_summary=[...],
  )
  ```

  ```json 401 theme={null}
  {
    "error": true,
    "status_code": 401,
    "error_type": "authentication_error",
    "message": "Could not validate credentials",
    "details": [
      {
        "type": "authentication_error",
        "message": "Could not validate credentials"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 403 theme={null}
  {
    "error": true,
    "status_code": 403,
    "error_type": "authorization_error",
    "message": "Insufficient OAuth scope for this endpoint",
    "details": [
      {
        "type": "authorization_error",
        "message": "Insufficient OAuth scope for this endpoint"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 404 theme={null}
  {
    "error": true,
    "status_code": 404,
    "error_type": "not_found_error",
    "message": "Patient not found",
    "details": [
      {
        "type": "not_found_error",
        "message": "Patient not found"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 422 theme={null}
  {
    "error": true,
    "status_code": 422,
    "error_type": "validation_error",
    "message": "Request validation failed (1 error)",
    "details": [
      {
        "type": "missing",
        "message": "Field required",
        "field": "patient_id",
        "location": ["body", "patient_id"],
        "input_value": null
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 429 theme={null}
  {
    "error": true,
    "status_code": 429,
    "error_type": "server_error",
    "message": "Rate limit exceeded",
    "details": [
      {
        "type": "rate_limit",
        "message": "Too many requests; retry after backoff"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 500 theme={null}
  {
    "error": true,
    "status_code": 500,
    "error_type": "internal_server_error",
    "message": "An internal server error occurred",
    "details": [
      {
        "type": "internal_server_error",
        "message": "An unexpected error occurred while processing your request"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```
</ResponseExample>
