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