anyproto/anytype-api/agent-skill

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Call Anytype's local HTTP API v2 directly — search, read, create and edit objects, queries, collections and chats over REST. Use when writing scripts, SDK code or curl against the API. For interactive note/task work prefer the `anytype` CLI and its skill (cmd/anytype/SKILL.md); this guide is the raw-HTTP layer beneath it.

Install

npx vskill@latest install anyproto/anytype-api/agent-skill

SKILL.md

Anytype API v2 — HTTP guide for agents

Local REST API at http://127.0.0.1:31009 (the Anytype app must be running). Every call sends Authorization: Bearer <key>; keys are created in the app (Settings → API keys) — the API mints none. Bodies are compact JSON, and every name this API owns is snake_case — params, fields and op names alike. (Inside an object's blocks and properties you are reading the AnyBlock format's content; property and type keys there are served as slugs by default, as display names under ?keys=name — see the properties bullet below.) Every list takes ?offset=&limit= (default 25, max 1000) and returns {data, total, offset, limit, has_more}.

First call: `GET /v2/auth/whoami`. A key may be scoped to particular spaces and to read-only. grant.scoped: false means the whole account; otherwise grant.spaces lists what you may touch and grant.permission whether you may write. Ask this instead of discovering limits through 403s (space_not_granted / write_not_granted — the message names the grant).

The data model in six ideas

  • Spaces contain everything; nearly every route is

/v2/spaces/{space_id}/…. GET /v2/spaces lists them.

  • An object = properties (typed key-values) + blocks (document

content). type is served as a type key (page, task) — never an id; on input a type NAME ("Meeting note") resolves too.

  • Properties are addressed by key — a snake_case slug minted once at

creation and frozen, so it survives renames (due_date, icon_emoji, manual_property). GET …/properties spells them that way, and served documents spell them that way by default; ?keys=name on a read serves the display-name vocabulary instead ("Due date") — pick slugs for anything long-lived, names for showing a user their own words. Input is forgiving everywhere and accepts BOTH: dueDate, DueDate, due-date, the display name Due date and even Дата выполнения all resolve to the one property they name; an input matching two properties is a 400 listing both, and an unknown one never silently creates anything. (One exception: the compact filter STRING validates before folding — spell a multi-word name with underscores there, Due_date.) Select/multi_select values are option names ("In progress", case-sensitive) — never option ids. A name the property does not already hold is refused — check it against GET …/properties/{key}/options, or resend with `?create_missing_options=true` to create it (a PATCH caps that at 64). Unknown property keys are rejected with a did-you-mean.

  • Blocks are a FLAT array in pre-order with an integer indent

(absent = 0) — no children key. Inline formatting is markdown inside text. Use block ids exactly as a read served them.

  • Title and description are not blocks — they live in properties

(name, description). A fresh object has zero blocks.

  • A query is a live query over a type (its type key is still set, the

name it carries internally); a collection is a hand-curated list (edited via add_items/remove_items). Chats store messages outside blocks, paged by order-id cursors.

Which operation

IntentCall
find objectsPOST …/{space_id}/search (or POST /v2/search across spaces — rows then carry space_id). Search with filters; don't enumerate GET …/objects
read one objectGET …/objects/{id} — start with ?outline=true
change property valuesPATCH op set_properties — add/remove for list values, set for scalars
complete a task objectset_properties ("set":{"done":true} or the status option) — a property, not a block edit
change a word/phraseop replace_text {find, replace} — id optional; never retype the block
toggle a checkbox blockop update_block {"match":"Draft timeline","set":{"checked":true}} — merge; text untouched. match or id, never both
add contentop insert_blocks with a markdown payload — write markdown, the server parses it
restructureops move_block / replace_subtree / delete_block (delete_block takes match too)
one table cellop set_cell — never rewrite the table
show/hide a view column, edit a viewop update_view — works on queries, collections and a type's default view (PATCH the type OBJECT id from GET …/types/{key})
add / reorder / remove a viewops insert_view (copy_from duplicates one) · move_view (position:"first" = default tab) · delete_view
create an objectPOST …/objects — shortcut {type, name, properties, markdown} covers most cases
delete an object you createdDELETE …/objects/{id} — archives (Bin, reversible in the app). Only works on objects THIS key created after provenance shipped; anything else → 403 not_created_by_this_key, permanently — don't retry, archive in the app instead. Ownership is matched on the app name EXACTLY (byte-for-byte — re-pair under the identical name to keep delete rights). User content only: system objects 403. Probe first with ?dry_run=true
curate a collectionPATCH ops add_items / remove_items on the collection object
read a query / collectionGET …/queries/{id}/objects · …/collections/{id}/objects (?view=, ?fields=)
new type / propertyPOST …/types · POST …/properties; select options ride the property, or ?create_missing_options=true mints them from values
upload a filePOST …/files (multipart or {"url":…}) → the id file blocks and chat attachments need
download a file or iconGET …/files/{file_id}/content; use a file id or a space/member's icon_image. Optional ?width= selects an image size. Supports ranges, conditional reads, and HEAD.
chatGET/POST …/chats/{id}/messages, POST …/read — see Chats
put an object in the sidebarPOST …/widgets {target, scope} — scope:"personal" is this account's own sidebar (any writer); scope:"space" is the shared one (owner/admin; not offered in one-to-one spaces). GET …/widgets lists both; PATCH/DELETE …/widgets/{id-or-target} change or remove one. Not is_favorite
comment on an objectPOST …/objects/{id}/discussion → {id}, then the chat routes with that id — see Chats

Read cheaply

  • GET …/objects/{id}?outline=true → every block's {indent, id, type}

plus its text truncated to 80 runes — structure + addressable ids at a fraction of the tokens. Follow up with ?block={id} for one subtree, or PATCH directly: editing needs no prior full read once you know the ids (but copy exact text from a full read — outline text may be cut).

  • When the request already quotes the text to change, skip the read

entirely: replace_text {find, replace} locates the block itself, and update_block/delete_block take match for the same job (one match, or a refusal listing the candidates).

  • ?include=properties or ?include=blocks reads half the object.

?format=md is a read-only markdown rendering.

  • Echo block ids back exactly as a read served them; if one is rejected as

unknown, re-read and use the fresh ids. ?ids=full is the backup/export shape — the read to archive or clone from, not needed for editing.

  • List/search rows are minimal {id, name, type}; add columns with

fields= (property keys) instead of GETting each object.

  • Every object read returns an etag (envelope + ETag header).

Edit: PATCH ops

PATCH …/objects/{id} body {"ops":[…]} — one atomic batch (≤512 ops, ≤256 blocks per op): any invalid op rejects the whole PATCH with ops[i]-addressed issues. Fourteen ops:

json
{ "ops": [
{ "op": "set_properties", "set": {"status": ["Done"]}, "unset": ["oldKey"],
"add": {"tags": ["urgent"]}, "remove": {"assignee": ["bafy…"]} },
{ "op": "update_block", "match": "Draft timeline", "set": {"checked": true} },
{ "op": "replace_text", "find": "Q3 report", "replace": "Q4 report" },
{ "op": "insert_blocks", "after": "b3", "markdown": "## Notes\n- first\n- second" },
{ "op": "move_block", "id": "b9", "inside": "b2", "position": "last" },
{ "op": "delete_block", "id": "b4", "recursive": true },
{ "op": "set_cell", "table_id": "t1", "row": "r2", "col": "c1", "value": "done" },
{ "op": "update_view", "columns": {"status": {"hidden": false}} },
{ "op": "insert_view", "name": "Board", "copy_from": "viewAll1",
"set": {"type": "kanban", "groupBy": "status"} }
] }

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/anyproto/anytype-api/agent-skill/badge)](https://verified-skill.com/skills/anyproto/anytype-api/agent-skill)

Something wrong with this skill or its page? Tell us.