---
title: "Lock board (set/change mode)"
method: POST
path: "/api/boards/{boardId}/lock"
tags: ["Boards"]
---

# Lock board (set/change mode)

`POST /api/boards/{boardId}/lock`

## Request

- Base URL: `https://cnvs.app`
- URL: `https://cnvs.app/api/boards/{boardId}/lock`
- Auth: none declared

Apply an access lock to the board. On an unlocked board: server generates an 8-char [a-z0-9] key, stores its SHA-256 hash, and returns the plaintext key ONCE. On an already-locked board: caller must supply the existing key via `X-Board-Key`; only the mode is updated.

**There is no recovery.** Losing the key loses the board.

## Request body

- object
  - `mode` 'write' | 'all', required: `write` = anyone can read, only key-holders can mutate. `all` = key required for both read and write.

## Response `200`

Lock applied. `key` is present only on first lock (server-generated).

- object
  - `mode` 'write' | 'all', required
  - `key` string: Plaintext access key — returned once. Server only stores SHA-256.

## Other responses

- `400`: Invalid input (missing or malformed board id).
- `401`: Board is access-locked and the request did not carry a valid key. `lockMode` tells the client whether to prompt for a code or just disable write UI.
- `403`: Existing key not supplied or incorrect on a re-lock.
- `404`: Board does not exist or was deleted within the 30-day tombstone window.
- `409`: Concurrent lock-state change; the row rotated between SELECT and UPDATE. Reload and retry.
- `429`: Rate limit exceeded. Standard REST/MCP: 60 requests/10s/board; valid X-Import-Token infrastructure tier: 600/10s/board; browser WebSocket always 60/10s/board. REST/MCP enforcement is soft per-isolate; WebSocket enforcement is strong per Durable Object.

---

[API](https://skmtc.dev/cnvs/apis/cnvs-app-http-api.md) · [All operations](https://skmtc.dev/cnvs/apis/cnvs-app-http-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cnvs/apis/cnvs-app-http-api/revisions/c8f2c3b7ff90?raw)
