REST API reference

Milanote API

11 endpoints for Milanote. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/milanote
Connects with
Your own Milanote account (email and password, Google or Apple)
Integration page
Milanote
Milanote Endpoints
Endpoint Access Description
list_boards read Your boards and nested sub-boards, with title, parent board and ID.
get_board read Every card on a board: notes, links, images, files, to-do lists and sub-boards.
search_boards read Find notes and boards by text across all your boards, like the in-app search.
export_board read Export a board in one of the formats Milanote offers.
create_board write New board, at the top level or nested inside another board.
add_note write Note card with text, placed on a board.
add_link write Link card for a web address, placed on a board.
upload_image write Image card from a file, placed on a board.
add_todo_list write To-do list card with tasks, each with an optional due date.
add_comment write Comment card on a board, or a reply in a comment thread, as you.
invite_editor write Invite someone by email to edit a board and its sub-boards.

POST https://cotlet.dev/api/v1/milanote/list_boards

Returns boards in the order they appear in Milanote, each with its parent so nesting is clear. Boards can sit inside boards, like folders, so use parent_board_id to walk down. Your Home board is not a regular board and is not listed.

Parameters

Parameters: list_boards
NameTypeDescription
parent_board_id string Only boards inside this board. Default: your boards at the top level.
limit integer Number of boards to return. Default: 50.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/list_boards \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("milanote", "list_boards")
Node.js
const result = await cotlet.call('milanote', 'list_boards');
CLI
cotlet call milanote list_boards

Example response

{
  "boards": [
    {
      "id": "b_7Kq2Lm",
      "title": "Brand refresh",
      "parent_board_id": null
    },
    {
      "id": "b_2Xn9Dc",
      "title": "Novel outline",
      "parent_board_id": null
    },
    {
      "id": "b_5Hc3Wp",
      "title": "Q1 campaign",
      "parent_board_id": null
    }
  ]
}

Get board

read

POST https://cotlet.dev/api/v1/milanote/get_board

Returns one entry per card with its type, text or URL, and ID, so other tools can point at it. To-do list cards include each task with its done state and due date. Sub-boards appear as cards with their own board_id; call get_board again to open one. Reads only, so it works on boards you can view as well as edit.

Parameters

Parameters: get_board
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
include_comments boolean Also return comment cards and their replies. Default: false.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/get_board \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"board_8c41d2"}'
Python
result = client.call("milanote", "get_board", {"board_id":"board_8c41d2"})
Node.js
const result = await cotlet.call('milanote', 'get_board', {"board_id":"board_8c41d2"});
CLI
cotlet call milanote get_board --data '{"board_id":"board_8c41d2"}'

Example response

{
  "board_id": "b_5Hc3Wp",
  "title": "Q1 campaign",
  "cards": [
    {
      "id": "c_41aF",
      "type": "note",
      "text": "Palette: warm greys with one orange accent."
    },
    {
      "id": "c_88bQ",
      "type": "link",
      "url": "https://example.com/type-specimen",
      "title": "Type specimen"
    },
    {
      "id": "c_12dK",
      "type": "board",
      "board_id": "b_5Hc3Xt",
      "title": "Social assets"
    }
  ]
}

POST https://cotlet.dev/api/v1/milanote/search_boards

Searches the board you have open and the contents of every other board you have created, as the Search icon in Milanote does. Results are sorted by last viewed unless you ask for last modified. Use get_board on a hit to read its cards.

Parameters

Parameters: search_boards
NameTypeDescription
query required string Text to look for.
sort enum last_viewed or last_modified. Default: last_viewed.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/search_boards \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"query"}'
Python
result = client.call("milanote", "search_boards", {"query":"query"})
Node.js
const result = await cotlet.call('milanote', 'search_boards', {"query":"query"});
CLI
cotlet call milanote search_boards --data '{"query":"query"}'

Example response

{
  "results": [
    {
      "board_id": "b_5Hc3Wp",
      "board_title": "Q1 campaign",
      "card_id": "c_41aF",
      "snippet": "Palette: warm greys with one orange accent."
    },
    {
      "board_id": "b_7Kq2Lm",
      "board_title": "Brand refresh",
      "card_id": "c_30pM",
      "snippet": "Color palette v2 from the workshop"
    }
  ]
}

POST https://cotlet.dev/api/v1/milanote/export_board

Runs the same export as the Export button on a board and returns the text, or a download link for word, pdf and png. Home boards cannot be exported. PDF and PNG are limited to a single page; Word spreads a large board over several pages.

Parameters

Parameters: export_board
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
format required enum markdown, plain_text, word, pdf or png.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/export_board \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"b_2Xn9Dc","format":"markdown"}'
Python
result = client.call("milanote", "export_board", {"board_id":"b_2Xn9Dc","format":"markdown"})
Node.js
const result = await cotlet.call('milanote', 'export_board', {"board_id":"b_2Xn9Dc","format":"markdown"});
CLI
cotlet call milanote export_board --data '{"board_id":"b_2Xn9Dc","format":"markdown"}'

Example response

{
  "board_id": "b_2Xn9Dc",
  "format": "markdown",
  "content": "# Novel outline\n\n## Act one\n\n- Maya finds the letter\n- The ferry leaves without her\n"
}

Create board

write

POST https://cotlet.dev/api/v1/milanote/create_board

Returns the new board ID for the tools that add cards. The board is private to you until you share it. It reaches no one, so it runs without asking; move it to the trash in Milanote to undo it.

Parameters

Parameters: create_board
NameTypeDescription
title required string Board title.
parent_board_id string Board to nest it in. Default: top level.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/create_board \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"title"}'
Python
result = client.call("milanote", "create_board", {"title":"title"})
Node.js
const result = await cotlet.call('milanote', 'create_board', {"title":"title"});
CLI
cotlet call milanote create_board --data '{"title":"title"}'

Example response

{
  "board_id": "b_9Rt4Zy",
  "title": "Location scout",
  "parent_board_id": null,
  "board_url": "https://app.milanote.com/b_9Rt4Zy"
}

Add note

write

POST https://cotlet.dev/api/v1/milanote/add_note

Adds one note card and returns its ID. On the free plan a note counts toward the 100 notes, images or links total. Other editors of the board see the card, but nobody is notified, so it runs without asking; drag it to the trash to undo it.

Parameters

Parameters: add_note
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
text required string Note text.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/add_note \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"board_8c41d2","text":"text"}'
Python
result = client.call("milanote", "add_note", {"board_id":"board_8c41d2","text":"text"})
Node.js
const result = await cotlet.call('milanote', 'add_note', {"board_id":"board_8c41d2","text":"text"});
CLI
cotlet call milanote add_note --data '{"board_id":"board_8c41d2","text":"text"}'

Example response

{
  "card_id": "c_62tN",
  "board_id": "b_5Hc3Wp",
  "type": "note",
  "text": "Kickoff moved to Tuesday."
}

Upload image

write

POST https://cotlet.dev/api/v1/milanote/upload_image

Adds one image card per call and returns its ID. On the free plan an image counts toward the 100 notes, images or links total, and file uploads are capped at 10. Nobody is notified, so it runs without asking; drag the card to the trash to undo it.

Parameters

Parameters: upload_image
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
file_base64 required string Image file contents, base64.
file_name string File name shown on the card, e.g. location-01.jpg.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/upload_image \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"board_8c41d2","file_base64":"file base64"}'
Python
result = client.call("milanote", "upload_image", {"board_id":"board_8c41d2","file_base64":"file base64"})
Node.js
const result = await cotlet.call('milanote', 'upload_image', {"board_id":"board_8c41d2","file_base64":"file base64"});
CLI
cotlet call milanote upload_image --data '{"board_id":"board_8c41d2","file_base64":"file base64"}'

Example response

{
  "card_id": "c_90uE",
  "board_id": "b_9Rt4Zy",
  "type": "image",
  "file_name": "location-01.jpg"
}

POST https://cotlet.dev/api/v1/milanote/add_todo_list

Creates one to-do list with all its tasks and returns each task ID. A due date makes Milanote remind whoever set it, by email, phone push or browser notification, as their settings say. Nobody is notified when the list is created, so it runs without asking; drag it to the trash to undo it.

Parameters

Parameters: add_todo_list
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
title string List title.
tasks required object Array of { text, due_date?, due_time? }; due_date is YYYY-MM-DD, due_time HH:MM for the reminder.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/add_todo_list \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"b_5Hc3Wp","title":"Client call, 12 Oct","tasks":[{"text":"Shorten the intro","due_date":"2026-10-16"},{"text":"Swap the hero image (Sam)","due_date":"2026-10-16","due_time":"10:00"}]}'
Python
result = client.call("milanote", "add_todo_list", {"board_id":"b_5Hc3Wp","title":"Client call, 12 Oct","tasks":[{"text":"Shorten the intro","due_date":"2026-10-16"},{"text":"Swap the hero image (Sam)","due_date":"2026-10-16","due_time":"10:00"}]})
Node.js
const result = await cotlet.call('milanote', 'add_todo_list', {"board_id":"b_5Hc3Wp","title":"Client call, 12 Oct","tasks":[{"text":"Shorten the intro","due_date":"2026-10-16"},{"text":"Swap the hero image (Sam)","due_date":"2026-10-16","due_time":"10:00"}]});
CLI
cotlet call milanote add_todo_list --data '{"board_id":"b_5Hc3Wp","title":"Client call, 12 Oct","tasks":[{"text":"Shorten the intro","due_date":"2026-10-16"},{"text":"Swap the hero image (Sam)","due_date":"2026-10-16","due_time":"10:00"}]}'

Example response

{
  "card_id": "c_55vG",
  "board_id": "b_5Hc3Wp",
  "title": "Call edits",
  "task_count": 2,
  "tasks": [
    {
      "id": "t_01",
      "text": "Shorten the intro",
      "due_date": "2026-10-16"
    },
    {
      "id": "t_02",
      "text": "Swap the hero image",
      "due_date": "2026-10-16"
    }
  ]
}

Add comment

write Confirm

POST https://cotlet.dev/api/v1/milanote/add_comment

Posts under your name; people in the thread and anyone you @mention are notified. A comment cannot be deleted from a thread afterwards, and only you can edit it. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: add_comment
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
text required string Comment text. @name tags a collaborator.
reply_to_id string Comment ID to reply to.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/add_comment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"board_8c41d2","text":"text"}'
Python
result = client.call("milanote", "add_comment", {"board_id":"board_8c41d2","text":"text"})
Node.js
const result = await cotlet.call('milanote', 'add_comment', {"board_id":"board_8c41d2","text":"text"});
CLI
cotlet call milanote add_comment --data '{"board_id":"board_8c41d2","text":"text"}'

Example response

{
  "comment_id": "m_31jB",
  "board_id": "b_5Hc3Wp",
  "text": "@Sam the new palette is on this board.",
  "notified": [
    "Sam"
  ]
}

Invite editor

write Confirm

POST https://cotlet.dev/api/v1/milanote/invite_editor

Sends the invitee an email with a link; they need a free Milanote account to edit. Sharing also applies to sub-boards, and your Home board cannot be shared. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: invite_editor
NameTypeDescription
board_id required string Board ID from list_boards or the board URL.
email required string Their email address.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/milanote/invite_editor \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"board_8c41d2","email":"jane@example.com"}'
Python
result = client.call("milanote", "invite_editor", {"board_id":"board_8c41d2","email":"jane@example.com"})
Node.js
const result = await cotlet.call('milanote', 'invite_editor', {"board_id":"board_8c41d2","email":"jane@example.com"});
CLI
cotlet call milanote invite_editor --data '{"board_id":"board_8c41d2","email":"jane@example.com"}'

Example response

{
  "board_id": "b_7Kq2Lm",
  "invited": "sam@example.com",
  "role": "editor",
  "status": "invited"
}