---
title: "Upload a board background image"
method: POST
path: "/projects/{id}/background-image"
---

# Upload a board background image

`POST /projects/{id}/background-image`

## Request

- Base URL: `https://craaft.io/api/v1`
- URL: `https://craaft.io/api/v1/projects/{id}/background-image`
- Auth: HTTP bearer

Board admins only (workspace owners/admins, or explicit board
admins). `multipart/form-data` with a single `file` part, max
10 MiB.

The declared part `Content-Type` must be one of `image/png`,
`image/jpeg`, `image/webp`, `image/gif` AND must match what the
leading bytes actually sniff as, so a renamed file is rejected
rather than stored. Returns the updated project.

## Response `200`

Updated project

- Project
  - `id` string, uuid, required
  - `workspaceId` string, uuid, required
  - `name` string, required
  - `description` string
  - `isFavorite` boolean
  - `publicToken` string: Non-empty when public sharing is on
  - `backgroundImage` string
  - `backgroundColor` string: Board background hex color (#rrggbb), empty when unset; mutually exclusive with backgroundImage
  - `colorScheme` string
  - `textColor` 'dark' | 'light'
  - `showMilestones` boolean: Whether the board's top bar shows the milestones button. Default true.
  - `showArchived` boolean: Whether the board's top bar shows the archived cards button. Default true.
  - `showFiles` boolean: Whether the board's top bar shows the files button. Default true.
  - `showStandup` boolean: Whether the board's top bar shows the standup button. Default true.
  - `showActivity` boolean: Whether the board's top bar shows the activity button. Default false. The /projects/{id}/activity feed answers either way.
  - `myRole` 'owner' | 'admin' | 'member': Caller's role in the project's *workspace* (distinct from myBoardRole).
  - `visibility` 'private' | 'workspace': `private` (default): only users with an explicit grant (plus workspace owners/admins) see the board. `workspace`: every workspace member is an implicit contributor.
  - `myBoardRole` 'admin' | 'contributor': Caller's effective role on the board. Workspace owners and admins are always `admin`; explicit grants resolve to `admin` or `contributor`; on a `workspace`-visibility board, plain workspace members default to `contributor`.
  - `canUploadAttachments` boolean: Whether cards on this board accept file attachments. Reflects the board's *workspace* plan (Pro), NOT the caller's own plan - so a Free user collaborating on a Pro workspace's board sees `true`. Matches the server's upload gate; the SPA uses it to show/hide the attachment dropzone.
  - `totalCards` integer
  - `columnCounts` object
  - `workspaceName` string: Workspace display name; populated on list responses.
  - `members` ProjectMemberPreview[]: Capped avatar-stack preview on list responses only.
    - `id` string, uuid, required
    - `name` string, required
    - `avatarUrl` string, required: Empty when no upload; otherwise /api/v1/users/{id}/avatar
  - `columns` Column[]
    - `id` string, uuid, required
    - `key` string, required: Stable identifier for cards.column
    - `title` string, required
    - `color` string: Optional palette token; empty for default
    - `position` number, required
    - `isDone` boolean
    - `cardLimit` integer, nullable
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required

## Other responses

- `400`: Unparseable multipart body, a missing or empty `file` part, a type outside the PNG/JPEG/WebP/GIF set, or a declared type that does not match what the leading bytes sniff as.
- `401`: Missing or invalid token
- `404`: Resource doesn't exist or caller isn't a member of its workspace
- `413`: File exceeds the 10 MiB limit

---

[API](https://skmtc.dev/craaft/apis/craaft-api.md) · [All operations](https://skmtc.dev/craaft/apis/craaft-api/llms.txt) · [OpenAPI document](https://skmtc.dev/craaft/apis/craaft-api/revisions/43e34309dfe2?raw)
