# Uploads — API reference

Getting bytes into Fylane without them touching the API.

## POST /v1/uploads

Returns a single-use, size-capped, pre-signed URL. Upload the bytes directly to it; they never pass through the API, which is why a 5 GB file and a 5 KB file cost the same to accept. Two variants share the endpoint: `multipart: true` answers with one pre-signed URL per part instead of a single PUT, and `from_url` has the platform fetch a public URL itself — the answer is then the completed `File`, not a session.

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | header | Required | Client-generated key, scoped to (organization, endpoint) and retained 24 hours. A replay with the same body returns the stored response without re-executing or re-billing; a replay with a different body returns 409. |

Request body

| Field | Type | Requirement | Description |
| --- | --- | --- | --- |
| `filename` | `string` | Optional |  |
| `byte_size` | `integer` | Optional | Declared size. The signed URL enforces it; a larger body is refused. |
| `mime_type` | `string` | Optional | Declared type. Verified against the bytes. |
| `multipart` | `boolean` | Optional | Ask for a multipart session: per-part pre-signed URLs (16 MB+ parts, at most 64), finished via `POST /v1/uploads/{upload_id}/complete-parts`. Parts fail and retry individually, and `POST /v1/uploads/{upload_id}/parts` re-mints fresh URLs — the resume path. |
| `from_url` | `string` (uri) | Optional | A public HTTPS URL for the platform to fetch server-side. Private networks and redirects are refused; the response is the completed, validated `File` rather than an upload session. |
| `project_id` | `string` | Optional | Defaults to the key’s project. |
| `validation` | `object` | Optional | Acceptance policy for this upload, judged against the detected bytes at completion — never against the declared type. A file that fails is recorded `rejected` with the findings, and completion answers `validation_failed`. |

Responses

| Status | Description |
| --- | --- |
| `200` | The `from_url` variant only: the URL was fetched, validated and completed in one step. |
| `201` | Session created. |
| `400` | Codes: invalid_request, unsupported_file, file_too_large, corrupted_file, encrypted_file, unsupported_operation. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `409` | Codes: idempotency_conflict, upload_session_consumed, conflict. |
| `413` | Codes: payload_too_large. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |

## GET /v1/uploads/{upload_id}

Retrieve an upload session

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `upload_id` | path | Required | Upload session identifier. |

Responses

| Status | Description |
| --- | --- |
| `200` | The session. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `404` | Not found. A resource belonging to another organization returns 404, never 403 — a 403 would confirm it exists. Codes: not_found. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |

## POST /v1/uploads/{upload_id}/parts

Fresh pre-signed URLs for every part of a multipart session — the resume path. Losing a connection loses only the parts in flight: re-mint, re-upload the missing parts, and complete.

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `upload_id` | path | Required | Upload session identifier. |
| `Idempotency-Key` | header | Required | Client-generated key, scoped to (organization, endpoint) and retained 24 hours. A replay with the same body returns the stored response without re-executing or re-billing; a replay with a different body returns 409. |

Responses

| Status | Description |
| --- | --- |
| `200` | One fresh URL per part. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `404` | Not found. A resource belonging to another organization returns 404, never 403 — a 403 would confirm it exists. Codes: not_found. |
| `409` | Codes: idempotency_conflict, upload_session_consumed, conflict. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |

## POST /v1/uploads/{upload_id}/complete-parts

Hand back the `{part_number, etag}` pairs storage answered each part with. The object is assembled, measured (the declared size was a promise; the measurement is what validation judges), and then the one standard completion runs — detection, policy, hash, duplicate detection, identical to a single PUT.

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `upload_id` | path | Required | Upload session identifier. |
| `Idempotency-Key` | header | Required | Client-generated key, scoped to (organization, endpoint) and retained 24 hours. A replay with the same body returns the stored response without re-executing or re-billing; a replay with a different body returns 409. |

Request body

| Field | Type | Requirement | Description |
| --- | --- | --- | --- |
| `parts` | array of `object` | Required |  |

Responses

| Status | Description |
| --- | --- |
| `200` | Assembled and completed. |
| `400` | Codes: invalid_request, unsupported_file, file_too_large, corrupted_file, encrypted_file, unsupported_operation. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `404` | Not found. A resource belonging to another organization returns 404, never 403 — a 403 would confirm it exists. Codes: not_found. |
| `422` | Codes: malware_detected, policy_violation, validation_failed, output_validation_failed, unsupported_input. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |

## POST /v1/uploads/{upload_id}/abort

Discards the parts uploaded so far. Sessions abandoned without an abort are swept automatically after a day.

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `upload_id` | path | Required | Upload session identifier. |
| `Idempotency-Key` | header | Required | Client-generated key, scoped to (organization, endpoint) and retained 24 hours. A replay with the same body returns the stored response without re-executing or re-billing; a replay with a different body returns 409. |

Responses

| Status | Description |
| --- | --- |
| `204` | Aborted; stored parts discarded. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `404` | Not found. A resource belonging to another organization returns 404, never 403 — a 403 would confirm it exists. Codes: not_found. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |

## POST /v1/files/{file_id}/complete

Tell the platform the bytes have landed. Detection, validation policy and (within the hash window) SHA-256 and duplicate detection all run here, against the bytes actually stored — never against what was declared. A file that fails its validation policy is recorded `rejected` and this call answers with the refusal.

Parameters

| Name | In | Requirement | Description |
| --- | --- | --- | --- |
| `file_id` | path | Required | File identifier. |
| `Idempotency-Key` | header | Required | Client-generated key, scoped to (organization, endpoint) and retained 24 hours. A replay with the same body returns the stored response without re-executing or re-billing; a replay with a different body returns 409. |

Responses

| Status | Description |
| --- | --- |
| `200` | The completed file, `ready` for jobs — carrying `duplicate_of` when another ready file in the project has identical content. |
| `400` | Codes: invalid_request, unsupported_file, file_too_large, corrupted_file, encrypted_file, unsupported_operation. |
| `401` | Codes: missing_credentials, invalid_api_key, expired_api_key, revoked_api_key, api_key_in_query. |
| `403` | Codes: insufficient_scope, ip_not_allowed, environment_mismatch, organization_suspended, forbidden, key_restricted. |
| `404` | Not found. A resource belonging to another organization returns 404, never 403 — a 403 would confirm it exists. Codes: not_found. |
| `422` | Codes: malware_detected, policy_violation, validation_failed, output_validation_failed, unsupported_input. |
| `429` | Rate limited or out of credits. Retry after the interval in `Retry-After`. Codes: key_spend_limit, rate_limited, concurrency_limit, credits_exhausted. |
| `500` | Codes: internal_error. |
| `503` | Codes: processing_unavailable, dependency_unavailable. |
| `504` | Codes: timeout. |
