> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.labric.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.labric.co/_mcp/server.

# Create an upload URL

POST https://platform.labric.co/api/v1/files/upload-url
Content-Type: application/json

Start an upload that sends the file bytes straight to storage.

Creates the file record and returns a signed URL that accepts the bytes as
the body of an HTTP PUT for the next 15 minutes. Send exactly the returned
headers on the PUT and no Authorization header, then confirm the upload to
make the file visible. The URL only creates the object, never replaces one,
and refuses bodies over 500 MB. Asking again for an instrument path whose
upload was never confirmed returns a fresh URL for the same file, so a
failed PUT can be retried. The SDK's files.upload() runs all three steps;
the [Upload files](https://docs.labric.co/upload-files) guide shows them
with curl.

At least one of job_execution_id and instrument_id is required: pass a
job_execution_id for an artifact of a job running in a sandbox, which also
records provenance linking the file to that execution, and pass an
instrument_id for data captured off-platform by an instrument the Sync app
cannot reach, which attaches the file to that instrument so instrument
triggers and parsers pick it up.

Requires an API key with the `write` scope.

Reference: https://docs.labric.co/api-reference/labric-api/files/create-upload-url

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Request

### Body (application/json)

This endpoint expects an object.

- `file_name` (string, required) — The file name to record, e.g. results.csv.
- `content_type` (string, optional, nullable) — MIME type of the file. Defaults to application/octet-stream, which is also substituted for types a browser could render as a page.
- `job_execution_id` (string, optional, nullable) — The job execution producing the file, for a job artifact.
- `instrument_id` (string, optional, nullable) — The instrument that captured the file, for off-platform data.

## Response

### 200

OK

- `file_id` (string, required) — The ID of the file record awaiting its bytes.
- `upload_url` (string, required) — Signed Google Cloud Storage URL. Send the file bytes as the body of an HTTP PUT to this URL with no Authorization header.
- `headers` (map from string to string, required) — Headers the PUT must carry exactly as given; the URL is signed for them. They set the Content-Type, let the object be created but not replaced, and cap the body at the platform's file size limit.
- `expires_at` (string, required) — When the upload URL stops working, as an ISO 8601 timestamp.

## Errors

### 400 Bad Request Error

Bad Request

- `detail` (string, required)

### 401 Unauthorized Error

Unauthorized

- `detail` (string, required)

### 403 Forbidden Error

Forbidden

- `detail` (string, required)

### 404 Not Found Error

Not Found

- `detail` (string, required)

### 409 Conflict Error

Conflict

- `detail` (string, required)

### 422 Unprocessable Entity Error

Unprocessable Content

- `detail` (list of map from string to any, required)

### 500 Internal Server Error

Internal Server Error

- `detail` (string, required)

## Examples

**Request**

```json
{
  "file_name": "tensile_batch_42.csv",
  "content_type": "text/csv",
  "job_execution_id": "8f1c2d3e-4b5a-4c6d-9e7f-0a1b2c3d4e5f"
}
```

**Response**

```json
{
  "file_id": "f3a9b2d7-8c4e-4a1f-9b2d-7e8c4e1f9b2d",
  "upload_url": "https://storage.googleapis.com/labric-files/f3a9b2d7-8c4e-4a1f-9b2d-7e8c4e1f9b2d?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Expires=900&X-Goog-Signature=3b7c9e1f",
  "headers": {
    "Content-Type": "text/csv",
    "x-goog-content-length-range": "0,524288000",
    "x-goog-if-generation-match": "0"
  },
  "expires_at": "2026-09-21T15:32:10.481Z"
}
```

**SDK Code**

```python
from labric import Labric

client = Labric(
    api_key="YOUR_TOKEN_HERE",
)

client.files.create_upload_url(
    file_name="tensile_batch_42.csv",
    content_type="text/csv",
    job_execution_id="8f1c2d3e-4b5a-4c6d-9e7f-0a1b2c3d4e5f",
)

```