---
title: Assets | FLORA API
description: Upload, retrieve, retry, and attach media assets.
---

Assets represent media files available to FLORA workflows. For user-supplied images or videos, create an asset, upload the bytes to the returned signed upload URL, then mark the asset complete. The `source` field must always be a string: either `"signed-url"` for direct upload, or an allowlisted HTTPS URL for server-side fetch.

## Reserve a signed upload

Terminal window

```
curl -X POST https://app.flora.ai/api/v1/assets \
  -H "Authorization: Bearer sk_live_XXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "signed-url",
    "workspace_id": "ws_XXXX",
    "file_name": "product.png",
    "content_type": "image/png",
    "folder": "api-uploads"
  }'
```

Response:

```
{
  "asset_id": "asset_...",
  "url": "https://ik.imagekit.io/flora/...",
  "status": "pending_upload",
  "upload": {
    "url": "https://...",
    "formFields": {},
    "fileField": "file"
  }
}
```

## Create from an allowlisted URL

If your source file is already available at an allowlisted HTTPS URL, pass that URL as `source`:

Terminal window

```
curl -X POST https://app.flora.ai/api/v1/assets \
  -H "Authorization: Bearer sk_live_XXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "https://media.flora.ai/example.png",
    "workspace_id": "ws_XXXX"
  }'
```

Do not pass objects such as `{ "url": "..." }`, local file paths, `data:` URLs, or placeholder strings such as `"upload"`, `"file"`, or `"local"` as `source`.

## Upload the file bytes

Submit the returned `upload.formFields` and file to `upload.url` as multipart form data. The upload target is external to the FLORA API, so do not include your FLORA authorization header in that request unless the returned upload instructions say to.

## Complete the asset

After uploading bytes, complete the asset:

Terminal window

```
curl -X POST https://app.flora.ai/api/v1/assets/asset_XXXX/complete \
  -H "Authorization: Bearer sk_live_XXXX"
```

A completed asset has `status: "ready"` and can be passed to technique inputs or attached to projects.

## List assets

Terminal window

```
curl "https://app.flora.ai/api/v1/assets?workspace_id=ws_XXXX&limit=10" \
  -H "Authorization: Bearer sk_live_XXXX"
```

## Retrieve an asset

Terminal window

```
curl https://app.flora.ai/api/v1/assets/asset_XXXX \
  -H "Authorization: Bearer sk_live_XXXX"
```

## Retry an upload

If a pending upload expires or fails, request fresh upload instructions:

Terminal window

```
curl -X POST https://app.flora.ai/api/v1/assets/asset_XXXX/retry \
  -H "Authorization: Bearer sk_live_XXXX"
```

Retry is only valid for supported asset lifecycle states. If the asset cannot be retried, the API returns a validation or lifecycle error.

## Common endpoints

| Method | Path                                                     | Description                                |
| ------ | -------------------------------------------------------- | ------------------------------------------ |
| POST   | `/api/v1/assets`                                         | Create an asset or reserve a signed upload |
| POST   | `/api/v1/assets/{asset_id}/complete`                     | Mark an uploaded asset complete            |
| GET    | `/api/v1/assets?workspace_id={workspace_id}&limit=10`    | List assets                                |
| GET    | `/api/v1/assets/{asset_id}`                              | Retrieve an asset                          |
| POST   | `/api/v1/assets/{asset_id}/retry`                        | Request new upload instructions            |
| POST   | `/api/v1/projects/{project_id}/assets/{asset_id}/attach` | Attach an asset to a project               |

## Common validation issues

- `source` is required and must be a string.
- Use `"signed-url"` when you need FLORA to reserve upload instructions for bytes you will upload yourself.
- Server-side URL fetch only accepts HTTPS URLs from allowlisted hosts. If the host is not allowlisted, either use the signed upload flow or send feedback with `kind: "missing_capability"`.
- `workspace_id` is required and must start with `ws_`.

## Notes

- Technique input URLs must be HTTPS.
- Wait for `status: "ready"` before using a newly uploaded asset as a workflow input.
- Keep the final `url` if you need to pass the asset directly to an `imageUrl` or `videoUrl` input.
