---
title: "Add, import and delete brand files"
description: "Upload, import by address and delete a brand's icon, logos, banner, favicon, collection files, team photos and guideline images."
---

> Documentation Index
> Fetch the complete documentation index at: https://tarkle.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Add, import and delete brand files

A brand's pictures and files reach a brand in one of two ways. You can upload the file in three steps, or give Tarkle the address of a public image and let it fetch the image in one call. You can also delete a file from a brand. Every call here sends your API key as `Authorization: Bearer <your-tarkle-key>`, and it names the workspace with its key in the `X-Workspace-Key` header. The person who made the key must be an owner or admin of that workspace. Every API key holds the `brands:files` scope. Keys have no scope picker: the only choice when a key is made is which workspaces it reaches. For the headers, see [Authentication](/docs/get-started/authentication).

## Choose the place

Every call names a `slot`, the place the file is for.

| `slot` | What it is for |
| --- | --- |
| `icon`, `main_logo`, `banner`, `social_image`, `favicon` | Replaces the brand's current file in that place. |
| `logo` | Adds an extra logo. A brand holds up to 20. |
| `asset` | Adds a file to a collection. A brand holds up to 30 collections, and each collection up to 200 files. |
| `team_photo` | Sets the photo of one team member. |
| `guideline_image` | Adds a picture to one guideline section. |

Any other `slot` answers `400 invalid_request`.

## 1. Start the upload

`POST /brands/{brand}/files` with the place the file is for.

```bash
curl -X POST -H "Authorization: Bearer $TARKLE_KEY" -H "X-Workspace-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"slot": "icon", "size": 18204, "filename": "icon.png"}' \
  https://tarkle.com/api/v1/brands/acme-bank/files
```

`size` and `filename` are optional. They let a file that is too large, or of a type the place does not take, be refused before you upload it. The answer holds:

- `file_id`, which you use in step 3. It only works for this brand and this place.
- `upload.method` (`PUT`) and `upload.url`. The address expires after `upload.expires_in` seconds (3,600).
- `max_bytes` and `extensions`: the largest size and the allowed file types for that place, or `null` for any type.

## 2. Send the file

`PUT` the file bytes to `upload.url`. Send the bytes as the body, with no `Authorization` header.

```bash
curl -X PUT --data-binary @icon.png "$UPLOAD_URL"
```

## 3. Complete the upload

`POST /brands/{brand}/files/{file_id}/complete`. Tarkle checks what was stored and attaches it to the brand.

```bash
curl -X POST -H "Authorization: Bearer $TARKLE_KEY" -H "X-Workspace-Key: $KEY" \
  https://tarkle.com/api/v1/brands/acme-bank/files/$FILE_ID/complete
```

The checks are the ones of the brand editor: the file's real type (from its first bytes, not its name), its size, and that it arrived. The limits by place are:

| Place | Types | Largest |
| --- | --- | --- |
| `icon`, `main_logo`, `logo`, `guideline_image` | PNG, JPG, WebP, SVG | 10 MB |
| `banner`, `social_image`, `team_photo` | PNG, JPG, WebP | 10 MB |
| `favicon` | PNG, JPG, WebP, SVG, ICO | 2 MB |
| `asset` | Any | 100 MB |

The five places on the brand row (`icon`, `main_logo`, `banner`, `social_image`, `favicon`) take no body. The others take these fields:

- `logo`: `name`, `type` (`primary`, `secondary`, `monochrome`, `reversed`, `icon`, `favicon`, `square` or `social media`) and `usage` (`digital`, `print` or `all purpose`).
- `asset`: `collection_id`, or `collection_name` to start a new collection, plus optional `name` and `type`.
- `team_photo`: `member_id`, or `member_name` when the member has no id.
- `guideline_image`: `section_id` (required), `kind` (`image`, `do` or `dont`, and `image` when left out) and `caption`.

The answer (`200`) holds `slot`, `file_id`, `size` and `already_attached`. It also holds the id of what was attached: `logo_id` for a logo, `collection_id` and `asset_file_id` for a collection file, `member_id` for a team photo, and `section_id` and `image_id` for a guideline image.

Completing the same file again answers the same with `already_attached: true` and changes nothing. A replaced icon, main logo, banner, social image, favicon or team photo is removed from storage unless the brand still uses it. A file that fails the checks is removed too.

## Import a picture by address

`POST /brands/{brand}/files/import` fetches a public image and attaches it in one call. Send `slot` and `url`, plus the fields the complete step takes for that place, such as `type` and `usage` for a logo or `member_id` for a team photo.

```bash
curl -X POST -H "Authorization: Bearer $TARKLE_KEY" -H "X-Workspace-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"slot": "favicon", "url": "https://example.com/favicon.png"}' \
  https://tarkle.com/api/v1/brands/acme-bank/files/import
```

The `url` must be an `https` address without a username or password, and it must point to a public image no larger than the place allows. The same checks as an upload run on the image. When the address cannot be read or the image is refused, nothing is attached and nothing is kept in storage. The answer is `201` and has the same fields as completing an upload.

## Delete a file

`DELETE /brands/{brand}/files?slot=...` takes one file off the brand. The query names the file:

| `slot` | Also send |
| --- | --- |
| `icon`, `main_logo`, `banner`, `social_image`, `favicon` | Nothing. The slot is enough. |
| `logo`, `asset` | `id`: the `logo_id` or the `asset_file_id` from `GET /brands/{brand}/assets`. |
| `team_photo` | `member_id`, or `member_name`. |
| `guideline_image` | `section_id` and `id`, the image id from the brand. |

```bash
curl -X DELETE -H "Authorization: Bearer $TARKLE_KEY" -H "X-Workspace-Key: $KEY" \
  "https://tarkle.com/api/v1/brands/acme-bank/files?slot=favicon"
```

The answer is `200` with `removed`, which holds the `slot` and the `removed_id`. The `removed_id` is the id of the logo, collection file, team member or image, and `null` for the five places on the brand row. The stored file is deleted too unless something of the brand still uses it. A file that is not there answers `404 not_found`.

The MCP server cannot delete a brand file. It adds brand images by address with `tarkle_import_brand_file`, and no tool it offers removes a brand file, so use this endpoint to delete one.

Deleting a whole brand is a different call, `DELETE /brands/{brand}`. It archives the brand; see [Create, delete and restore brands](/docs/api/brands/create-and-delete).

## Team photos and guideline images in a brand request

`POST /brands` and `PATCH /brands/{brand}` also take pictures by address: a team member's `photo_url` and a guideline section's `images`, each with a `url`, a `kind` and a `caption`. Tarkle fetches them after the text is saved, with the same checks as an upload. A request holds up to 12 pictures. A picture that fails is listed in `pictures`. See [Update a brand](/docs/api/brands/update-a-brand).

## Activity and webhooks

An upload that attaches a file, an import and a delete are recorded in the workspace Activity as `brand.updated`. Each one fires a `brand.updated` [webhook](/docs/api/webhooks) event. Completing a file that is already attached fires nothing.

## Errors

Match on `code` to tell errors apart. The answers that apply to this page are:

| Answer | Meaning |
| --- | --- |
| `400 invalid_request` | The body, the `slot`, the `url`, a query value or the `file_id` is wrong, or the `file_id` was made for another brand or place. |
| `403 forbidden` | The person who made the key is not an owner or admin of the workspace. |
| `403 no_access` | The key cannot reach the workspace named in `X-Workspace-Key`. |
| `404 not_found` | The brand, team member, guideline section or file is not in this workspace. |
| `409 file_not_uploaded` | Nothing was found at the upload address. `PUT` the file, then complete the upload again. |
| `409 conflict` | The place is full: a brand holds 20 extra logos, 30 collections, and 200 files in a collection, and a guideline section has a set number of images. It also answers this when the brand still holds images from the older editor, which blocks `asset` uploads. Open the brand in the app once to move them into collections. |
| `413 file_too_large` | The declared `size` is over the limit for that place. See [file_too_large](/docs/api/errors/file_too_large). |
| `422 invalid_file` | The stored file is too large, empty or not a real file of an allowed type, and it is removed. An import that cannot read an image at its address answers the same way. |
| `502 storage_unavailable` | Tarkle could not prepare the upload or store the image. Nothing was attached; try again. |

The full list of codes is in [Errors](/docs/api/errors).

Source: https://tarkle.com/docs/api/brands/files/index.mdx
