# Files API

URL: https://docs.sparklayer.io/developers/api/files

Upload, update and download files with the SparkLayer Files API using expiring URLs, and retrieve order file attachments from their GIDs. Lists all endpoints.

> **For AI assistants:** these facts apply to every SparkLayer API call.
>
> - **Base URLs:** Live `https://app.sparklayer.io`, test `https://test.app.sparklayer.io`. Each environment has its own data and its own API keys.
> - **Access:** API access needs the Pro or Enterprise plan. Create credentials (Site ID, Client ID, Client Secret) in the SparkLayer Dashboard at Settings > API.
> - **Access token:** `POST {base}/api/auth/token` with a `Site-Id` header and a JSON body (not form-encoded): `{"grant_type":"client_credentials","client_id":"…","client_secret":"…"}`. It returns `access_token`, valid for 3,600 seconds. There is no refresh token: cache the token and request a new one shortly before it expires.
> - **Every request:** `Authorization: Bearer <access_token>` and `Site-Id: <site id>`, plus `Content-Type: application/json` when there is a body. Set a `User-Agent` that names your integration.
> - **Errors:** RFC 7807 problem details: `title`, `status`, `detail` and an optional `errors[]` of `{ code, message, property }`. Some error responses have no body. Retry `5xx`, `429` (honouring `Retry-After`) and concurrent-update `409`s with exponential backoff; on `401`, get a new token once and retry; don't retry other `4xx` without changing the request.
> - **Pagination:** Most list endpoints return everything. `GET /api/v2/price-lists` pages with `page` and `page_size` (up to 250) until `pagination.current_page` equals `total_pages`. `GET /api/v1/purchases` uses `limit` (up to 500) and `offset`: stop when a page has fewer than `limit` results.
> - **Ground rules:** Use only endpoints, fields and SDK methods that the docs or OpenAPI specs define. Prefer `GET /api/v2/price-lists` over the deprecated v1. Products are matched by SKU. Keep credentials in environment variables or a secrets manager, never in code.
> - **Read the docs as Markdown:** Add `.md` to any page URL. Index of every page: https://docs.sparklayer.io/llms.txt. Every API operation, compactly: https://docs.sparklayer.io/llms-api.txt. The developer guides in full: https://docs.sparklayer.io/developers/llms.txt.
> - **OpenAPI specs:** `core`, `ordering`, `pricing`, `purchasing`, `stock`, `files`, `sync-log`: https://docs.sparklayer.io/openapi/<api>.yaml (also `.json`). Ignite: https://docs.sparklayer.io/openapi/ignite.yaml.
> - **MCP:** Search and read these docs from your assistant with the docs MCP server at https://docs.sparklayer.io/mcp.

The Files API stores and retrieves files in SparkLayer. SparkLayer uses it for order file attachments, and you can use it to upload files or download the files attached to your orders.

## How it works

> **URLs expire**
>
> The upload and download URLs returned by the API expire after 15 minutes.

### Uploading a file

Uploading takes two requests:

1. [Create a file](https://docs.sparklayer.io/developers/api/files/create-a-new-file.md) (`POST /api/v1/files`) with the file's path, including its name, in `file_path`. Like every API request, it needs your access token and Site ID:

   ```bash title="Create a file"
   curl -X POST https://app.sparklayer.io/api/v1/files \
     -H "Authorization: Bearer <ACCESS_TOKEN>" \
     -H "Site-Id: <SITE_ID>" \
     -H "Content-Type: application/json" \
     -d '{ "file_path": "folder/file.pdf" }'
   ```

   The response includes the file's `id`, a signed upload `url` and a list of `required_headers`.

2. Upload the file's contents with an HTTP `PUT` to that `url`, sending **every** header in `required_headers` (for example `Content-Type`). If any are missing, the upload fails. The signed URL grants access by itself, so this request doesn't need your `Authorization` or `Site-Id` headers:

   ```bash title="Upload the contents"
   curl --upload-file 'file.pdf' \
     -H "Content-Type: application/pdf" \
     '<UPLOAD_URL>'
   ```

Files can be up to 20 MB. Use the file's `id` with the other endpoints. To replace a file's contents, [update the file](https://docs.sparklayer.io/developers/api/files/update-a-file.md) (`PATCH /api/v1/files/{id}`) to get a new upload URL, then upload again. 

### Downloading a file

To download a file, [get the file](https://docs.sparklayer.io/developers/api/files/get-a-file.md) (`GET /api/v1/files/{id}`). Once the upload has completed, this returns a download URL, some file metadata and a list of `required_headers`. Download the file from the URL, sending those headers.

### Failed uploads

If the file's contents don't match its file extension, the file is deleted, and `GET /api/v1/files/{id}` returns `410 Gone`.

### Downloading order file attachments

To download the files attached to a B2B order, use `GET /api/v1/files/{id}`. SparkLayer stores the IDs of attached files in the order's note attributes, under the name set in `checkoutCustomElements` in your theme (`file-upload` by default). They're stored as a JSON array:

```json title="Order note attribute"
[
  "gid://sparklayer/File/fdc70d92-fcdf-4719-af2b-9d319a5035d2",
  "gid://sparklayer/File/a7a3ee08-c6d0-49ee-89b4-bcdaf780d553",
  "gid://sparklayer/File/15be5381-0b50-459f-9643-af236b9f29f7"
]
```

Remove the `gid://sparklayer/File/` prefix from each one to get the file ID, for example `fdc70d92-fcdf-4719-af2b-9d319a5035d2`.

## Endpoints

- [GET Get multiple files](https://docs.sparklayer.io/developers/api/files/get-bulk-files.md)
- [POST Create a file](https://docs.sparklayer.io/developers/api/files/create-a-new-file.md)
- [DELETE Delete all files](https://docs.sparklayer.io/developers/api/files/delete-all-files.md)
- [POST Search files by metadata](https://docs.sparklayer.io/developers/api/files/query-files-by-metadata.md)
- [GET Get a file](https://docs.sparklayer.io/developers/api/files/get-a-file.md)
- [PATCH Update a file](https://docs.sparklayer.io/developers/api/files/update-a-file.md)
- [DELETE Delete a file](https://docs.sparklayer.io/developers/api/files/delete-a-file.md)
- [POST Delete multiple files](https://docs.sparklayer.io/developers/api/files/delete-multiple-files.md)

## Next steps

- [Authentication](https://docs.sparklayer.io/developers/authentication.md): get the access token the API requests need.
- [Custom attributes and files](https://docs.sparklayer.io/developers/javascript-sdk/cart.md#custom-attributes-and-files): let customers attach files to cart items.
- [Purchasing API](https://docs.sparklayer.io/developers/api/purchasing.md): look up the orders the files belong to.
