---
title: "Get a signed upload URL for large file ingest"
method: POST
path: "/v1/data/ingest/upload-url"
tags: ["v1 data"]
---

# Get a signed upload URL for large file ingest

`POST /v1/data/ingest/upload-url`

**Step 1 of 2** — Obtain a time-limited signed URL for uploading a file
    directly to cloud storage (GCS).

    Use this instead of `/ingest` when the payload is large (e.g. > 32 MB)
    to avoid sending the entire file through the API server.

    **Flow:**
    1. Call this endpoint → receive `upload_url`, `job_id`, `object_key`
    2. HTTP **PUT** the raw file bytes to `upload_url`
    3. Call `/ingest/confirm-upload` with the `job_id` and `object_key`
       to kick off the processing pipeline

    The signed URL expires after the time indicated by `expires_in` (default 1 hour).

## Request body

- UploadUrlRequest — Request model for obtaining a signed upload URL
  - `user_id` string, required — User ID (always required)
  - `persona_id` string, nullable — Optional persona ID. If provided, data is ingested to this persona
  - `project_id` string, nullable — Optional project ID. If provided, data is ingested to this project
  - `content_type` string, nullable — Content category: 'text', 'image', 'video', 'pdf', 'audio', 'messages', 'file'. If omitted, the category is auto-detected after the file is uploaded.
  - `content_description` string, nullable — Optional description of the content being ingested
  - `session_id` string, nullable — Session ID for grouping related ingested content
  - `timestamp` string, nullable — ISO-8601 timestamp to preserve original data moment
  - `filename` string, nullable — Filename of the file to upload
  - `callback_url` string, nullable — Optional URL the server will POST to when the job reaches a terminal state.
  - `notification_email` string, email, nullable — Optional email address to notify when the job reaches a terminal state.

## Response `200`

Successful Response

- UploadUrlResponse — Response model for signed upload URL
  - `upload_url` string, required — Signed URL for uploading the file via HTTP PUT
  - `job_id` string, required — Job ID to use when confirming the upload
  - `object_key` string, required — GCS object key where the file will live
  - `expires_in` integer, required — Seconds until the upload URL expires
  - `success` boolean — Whether the URL was generated

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `404` — User/Persona/Project Not Found
- `422` — Validation Error
- `500` — Internal Server Error

---

[API](https://skmtc.net/elicitlabs/apis/elicit-labs-api.md) · [All operations](https://skmtc.net/elicitlabs/apis/elicit-labs-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/elicitlabs/elicit-labs-api/revisions/27701839a070/schema)
