API Reference
Authentication
All API endpoints require session authentication. You must be logged in via the web interface, or send the session cookie with your requests.
For programmatic access, authenticate first:
# Login and save cookies
curl -c cookies.txt -X POST https://your-yando-instance/accounts/login/ \
-d "[email protected]&password=yourpassword" \
-H "Referer: https://your-yando-instance/"
Then include -b cookies.txt in subsequent requests.
Rate Limiting
API endpoints are rate-limited per user. If you exceed the rate limit, you'll receive a 429 Too Many Requests response.
| Scope | Limit |
|---|---|
| General API requests | 100 / hour |
| Board create | 30 / hour |
| Board delete | 10 / hour |
| Board import | 20 / hour |
| Project create | 20 / hour |
| Project delete | 10 / hour |
The specific limits are separate allowances — creating a board does not use up your general 100/hour.
Keeping well under the limit. Adding objects counts against the general allowance, so creating them one request at a time is what usually exhausts it. Use the bulk object creation endpoint below (POST /api/boards/{board_id}/objects/bulk/) to add many objects in a single request, and target zones by name rather than fetching the board to look up a zone ID. Together these take a typical "create a board and fill it with 16 notes" workflow from around 34 requests down to 3.
Limits reset on a rolling one-hour window. If your account has a legitimate need for higher throughput — a demo environment or an internal integration — an administrator can exempt it from rate limits.
POST /api/boards/import/
Create a new board from exported JSON data.
Request
Accepts two content types:
JSON body (application/json):
curl -b cookies.txt -X POST https://your-yando-instance/api/boards/import/ \
-H "Content-Type: application/json" \
-H "X-CSRFToken: <token>" \
-d @board-export.json
File upload (multipart/form-data):
curl -b cookies.txt -X POST https://your-yando-instance/api/boards/import/ \
-H "X-CSRFToken: <token>" \
-F "[email protected]"
Query Parameters
| Parameter | Type | Description |
|---|---|---|
template |
string | Template name or UUID to override the JSON template |
title |
string | Override the board title from the JSON |
description |
string | Override the board description |
Response (201 Created)
{
"id": "a1b2c3d4-...",
"title": "My Board",
"description": "Board description",
"template": "Business Model Canvas",
"object_count": 15,
"url": "/boards/a1b2c3d4-.../"
}
Errors
| Status | Description |
|---|---|
| 400 | Invalid JSON, validation error, or missing required fields |
| 403 | Authentication required |
POST /api/boards/{board_id}/objects/bulk/
Create many objects on a board in a single request.
Use this instead of calling POST /api/boards/{board_id}/objects/ in a loop. Each request counts against your rate limit, so filling a 16-note board costs 1 request this way instead of 16.
Request
curl -b cookies.txt -X POST \
https://your-yando-instance/api/boards/{board_id}/objects/bulk/ \
-H "Content-Type: application/json" \
-d '{
"objects": [
{
"object_type": "sticky_note",
"zone": "Strengths",
"data": {"text": "Strong brand recognition", "color": "#7BC950"}
},
{
"object_type": "sticky_note",
"zone": "Weaknesses",
"data": {"text": "Thin margins", "color": "#FF6B6B"}
}
]
}'
Object Fields
| Field | Required | Description |
|---|---|---|
object_type |
Yes | sticky_note, text_box, shape, line, or image |
data |
Yes | Type-specific properties — text and color for a sticky note |
zone |
No | Zone name (case-insensitive) or UUID on the board's template |
zone_id |
No | Zone UUID. Takes precedence over zone |
x, y |
No | Position. Derived from the zone when omitted |
width, height |
No | Size. Defaults to 200×150 for sticky notes, 300×100 for text boxes |
rotation |
No | Degrees (default 0) |
opacity |
No | 0.0–1.0 (default 1.0) |
Targeting zones by name. Passing zone: "Strengths" saves you fetching the board first to find its UUID. An unknown name returns a 400 listing the zones that do exist.
Automatic placement. When you give a zone and omit x/y, the server positions each object inside that zone, spacing successive objects so they don't overlap. Supply explicit coordinates to override this.
Limits. Between 1 and 200 objects per request. Send larger imports in chunks.
Response (201 Created)
{
"count": 2,
"created": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"object_type": "sticky_note",
"x": 40.0,
"y": 30.0,
"width": 200.0,
"height": 150.0,
"data": {"text": "Strong brand recognition", "color": "#7BC950"},
"zone_name": "Strengths",
"version": 1
}
]
}
Objects are returned in the order you sent them. Collaborators with the board open see them appear live.
Errors
The request is atomic — if any object is invalid, none are created:
| Status | Description |
|---|---|
| 400 | Empty list, more than 200 objects, unknown zone name, or an invalid entry |
| 403 | You do not have editor access to this board |
| 404 | Board not found |
Validation errors name the offending entry, for example:
{"error": "Object at index 1: Zone 'Sxrengths' does not exist on this board's template. Available zones: Strengths, Weaknesses, Opportunities, Threats"}
POST /api/boards/{board_id}/resize/
Resize a board's canvas dimensions.
Request
curl -b cookies.txt -X POST \
https://your-yando-instance/api/boards/{board_id}/resize/ \
-H "Content-Type: application/json" \
-H "X-CSRFToken: <token>" \
-d '{"width": 4000, "height": 2400}'
Response (200 OK)
{
"id": "a1b2c3d4-...",
"canvas_width": 4000,
"canvas_height": 2400
}
GET /api/boards/{board_id}/snapshots/
List all snapshots for a board, ordered by creation date (newest first).
Request
curl -b cookies.txt \
https://your-yando-instance/api/boards/{board_id}/snapshots/
Response (200 OK)
[
{
"id": "s1n2a3p4-...",
"created_at": "2026-02-21T08:00:00Z",
"object_count": 24,
"board_version": 15,
"change_summary": {
"added": {"sticky_note": 2},
"edited": {"text_box": 1},
"deleted": {}
}
}
]
GET /api/boards/{board_id}/snapshots/{snapshot_id}/
Retrieve a single snapshot's full data.
Request
curl -b cookies.txt \
https://your-yando-instance/api/boards/{board_id}/snapshots/{snapshot_id}/
Response (200 OK)
Returns the full snapshot including snapshot_data containing the complete board state at that point in time.
POST /api/projects/{project_id}/pages/import/
Import markdown files as project pages.
Request
Upload one or more .md or .markdown files:
curl -b cookies.txt -X POST \
https://your-yando-instance/api/projects/{project_id}/pages/import/ \
-H "X-CSRFToken: <token>" \
-F "[email protected]" \
-F "[email protected]"
Response (201 Created)
{
"pages_created": 2,
"pages": [
{
"id": "p1a2g3e4-...",
"title": "Notes",
"url": "/projects/.../pages/p1a2g3e4-.../"
}
],
"errors": []
}
Status Codes
| Status | Description |
|---|---|
| 201 | All files imported successfully |
| 207 | Partial success - some files imported, some had errors |
| 400 | No files provided or all files failed |
| 403 | Not an owner or editor of the project |
| 404 | Project not found |
JSON Export Schema Reference
When exporting a board to JSON, the structure is:
{
"board": {
"title": "Board Title",
"description": "Optional description",
"template": "Template Name or null",
"canvas_width": 3200,
"canvas_height": 1800
},
"zones": {
"Zone Name": [
{
"type": "sticky_note",
"x": 100,
"y": 200,
"width": 200,
"height": 150,
"rotation": 0,
"data": {
"text": "Content here",
"color": "#FFEB3B"
}
}
]
},
"unzoned_objects": [
{
"type": "text_box",
"x": 500,
"y": 100,
"width": 300,
"height": 50,
"data": {
"text": "Unzoned text"
}
}
]
}
Object Types
| Type | Data Fields |
|---|---|
sticky_note |
text, color |
text_box |
text, fontSize, fontWeight |
shape |
shapeType (rectangle, circle, triangle, line), fill, stroke |