---
title: "Assets: Files"
url: "https://fileflare.io/docs/api-assets-files/"
description: "API reference for uploading and creating file assets in Fileflare via the API."
published: "2026-03-27T16:26:36+00:00"
modified: "2026-06-24T14:43:55+00:00"
---

Uploading a file is a three-step flow:

1. request a signed (multipart) upload
2. PUT each part of the file directly to storage
3. confirm the upload

This avoids streaming large files through Fileflare’s servers.

Requires [Bearer authentication](https://fileflare.io/docs/api-authentication/) with your Fileflare key. Rate-limited to 60 requests per minute.

## Step 1 — Request a signed upload

```
POST https://app.digital-downloads.com/api/v1/assets/signed
```

### Body (JSON)

- `name` (string, required) — the filename customers will see
- `size` (integer, required) — file size in bytes
- `mime` (string, required) — MIME type, e.g. `application/pdf`

```
curl -X POST https://app.digital-downloads.com/api/v1/assets/signed \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-book.pdf", "size": 10485760, "mime": "application/pdf"}'
```

### Response — 200 OK

```
{
  "chunk_size": 100000000,
  "upload_id": "2~aBcD...",
  "urls": [
    { "start": 0, "end": 10485760, "part": 1, "url": "https://<bucket>...&partNumber=1&uploadId=..." }
  ],
  "id": "82664d96-6dfd-4343-96b0-05c46f412a5b",
  "file_url": "https://app.digital-downloads.com/embedded/assets/82664d96-6dfd-4343-96b0-05c46f412a5b"
}
```

- `chunk_size` — fixed part size in bytes (currently 100 MB / `100000000`). The file is split into parts of this size; the final part is whatever remains.
- `upload_id` — the multipart upload ID. Pass it back in Step 3.
- `urls` — one entry per part. Each entry has `part` (the part number, 1-indexed; use as `PartNumber` in Step 3), `start`/`end` (the byte range of the file this part covers; `end` is exclusive), and `url` (the presigned PUT URL, valid for 12 hours).
- `id` — the Fileflare asset UUID. Use this in the Step 3 path.
- `file_url` — the asset’s location in Fileflare (informational).

A small file returns a single-entry `urls` array (one part covering the whole file).

## Step 2 — PUT each part to storage

For each entry in `urls`, PUT the file’s `start`–`end` byte range to that entry’s `url`, and **read the `ETag` from the response headers** — you’ll need it in Step 3.

```
# Part 1 = bytes [start, end) of the file. -D - prints response headers so you can read the ETag.
curl -X PUT "<urls[0].url>" --data-binary @part-1.bin -D -
# ...repeat for each entry in urls, slicing the file at each part's start/end.
```

## Step 3 — Confirm the upload

```
curl -X POST https://app.digital-downloads.com/api/v1/assets/$ASSET_ID/uploaded \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"upload_id": "2~aBcD...", "parts": [{"PartNumber": 1, "ETag": "\"abc...\""}]}'
```

### Body (JSON)

- `upload_id` (string, required) — the value returned from Step 1.
- `parts` (array, required, min 1) — one entry per part you PUT in Step 2.
- `parts.*.PartNumber` (int, required) — **1-indexed**; the `part` value from the matching `urls` entry.
- `parts.*.ETag` (string, required) — the `ETag` response header from that part’s PUT. May be sent with or without storage’s surrounding quote characters.

### Response — 201 Created

Empty body.

### Headers

Include `Accept: application/json`. Without it, validation errors are returned as a **302 redirect to the dashboard** instead of a JSON error body (a Laravel quirk shared with the attach/detach endpoints).

## Common errors

**Step 1 — `/assets/signed`**

- **402** — your storage quota is full. Free up space, upgrade, or connect your own S3.
- **422** — `name`, `size`, or `mime` is missing.

**Step 3 — `/uploaded`**

- **422** — `upload_id` is missing, or a `parts.*.ETag` / `parts.*.PartNumber` is missing or the wrong type.
- **500 “Server Error”** — `parts` is omitted or empty. Only the individual `parts.*` items are validated, so an entirely missing `parts` array slips past validation and fails downstream. In practice a 500 here means the `parts` payload is missing or malformed.

## Notes

- If the upload fails or you want to abandon it, call `POST /api/v1/assets/{asset}/cancel` to free the placeholder.

## Keep learning

- [Create a URL asset (no upload)](/docs/api-assets-url-assets/)
- [Other upload methods](/docs/methods-to-upload-add-files-to-fileflare/)
