Skip to content
Reference › Web API
Docs › Reference › Web API

Web API

Each call below is one HTTPS request to https://spacesheep.dev/v1: the same call as its MCP tool and its CLI command, with the same inputs and the same refusals. The whole web API as OpenAPI 3.1 is /v1/openapi.json, and the server's own table is /v1/doors.json. Both list only the calls the server runs today.

Sign a request

  • An API key, as Authorization: Bearer ss_…. Make one at Settings → API keys.
  • An OAuth access token from an app you connected (Claude, ChatGPT, Gemini, Grok), sent the same way.
  • A browser signed in to spacesheep.dev sends its session. A change sent from another site is refused.
curl https://spacesheep.dev/v1/spaces \
  -H "Authorization: Bearer ss_…"

Where inputs go

  • Each {…} in a route is an input. A space there is its uuid, @handle/slug or link, sent as one encoded part (%40you%2Fnotes).
  • A team, group or member there is its id. To name one instead, send the name in the path and again as team, group or member in the query or body.
  • The other inputs go in the query or in a JSON object body: each call says which. In the query, repeat a key for a list; true, false and numbers are read as the input takes them.
  • An input in the path and again in the query or body, with another value, is refused.
curl -X POST https://spacesheep.dev/v1/spaces/<space uuid>/comments \
  -H "Authorization: Bearer ss_…" \
  -H "Content-Type: application/json" \
  -d '{"body": "…"}'

Answers and refusals

An answer is a JSON object, with status 200. A refusal is a JSON object too, with the HTTP status of its code: {"code": "not_found", "message": "…", "violations": [{"field": "…", "message": "…"}]}. Branch on code, show message to a person, and read violations for the input that broke a rule. rate_limited also sends Retry-After, in seconds. Any call can refuse with insufficient_scope, internal, payload_too_large, unauthenticated.

CodeStatusWhat it means
invalid400An input broke a rule (violations names it when it can). Fix it and send again.
unauthenticated401No credential, or one that expired or was revoked. Sign in, or send a valid key.
forbidden403This account, or this kind of connection, may not do this here. Resending won't help.
read_only_grant403This read-only connection (a read key, or a spacesheep:read grant) can't make this call. Use a full key.
insufficient_scope403This key opens only streams or session hooks, never calls. Use a full key.
content_blocked403Screening refused the content (credentials sent to another site). Change it, or ask support to review it.
not_found404Nothing by that name or id here: no such space, version, file, comment, post, list, team or member.
conflict409The space has a newer version than your save builds on. Read it again, keep both changes, send it as parent.
turn_held409Someone's Shepherd is changing this space now. Wait for that turn to end, read it again, then resend.
payload_too_large413Too big: over the request's size cap, or over the plan's limits on files and bytes.
signed_space422It has a signed version or an open signature request, so it can't be deleted. Archive it instead.
wrong_kind422Not on this kind of space: a flock isn't archived, for one.
answer_too_large422The answer is too big for this call (over 1 MB). Open the space's address instead.
rate_limited429Too many calls too fast. Wait as long as Retry-After or the message says, then send again.
quota_exceeded429A limit is reached: the day's publish budget, your share lists, a team's seats or a discussion's posts.
suspended451The space was taken down, so it can't be changed. The message says where to appeal.
publish_failed500The publish didn't finish, and nothing was saved. Try again.
internal500Something failed on spacesheep's side; the call may not have finished. Read before you try again.
unavailable503A service behind the call is down or unreachable. Try again soon.

Publish and change a space

POST /v1/spaces

Publish files as a new space: one HTML file, or a folder with an index.html. Private unless you say who can open it.

In a JSON body
title, emoji, description, visibility, listed, team, team_id, team_access, design_system, archived, files (required), label, client, slug, people, people_ids, org
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
content_blocked (403), forbidden (403), invalid (400), publish_failed (500), quota_exceeded (429), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_space · CLI spacesheep spaces create
Every input
InputWhereTakesWhat it is
titlebodya titleIts title, as lists and link previews show it. (at most 200 characters)
emojibodytextOne emoji. (at most 16 characters)
descriptionbodytextOne line on what it is. (at most 300 characters)
visibilitybodyone of private, members, signed_in, publicWho can open a space.
listedbodytrue or falseListed in search and on the owner's profile (public spaces only).
teambodyteam nameIts team, when it lives in one.
team_idbodyteam idteam by its id, instead of its name.
team_accessbodyone of view, editWith a team: what its members may do. View (read and comment) when left out.
design_systembodytextA design system of yours, by name or id: later edits keep its look.
archivedbodytrue or falseWhether it's archived: put away, not served, out of lists unless asked for. Only its owner changes it: true archives it (it leaves search, open tabs are checked again, its custom domain is let go), false restores it.
filesbodylist of filesIts files: an index.html at least. (required)
files[].pathbodytextIts path inside the space: index.html, img/hero.jpg. (required; at most 512 characters)
files[].contentbodyHTMLText, as it is.
files[].staged_shabodytextWhat an upload staged: its staged sha.
files[].databodybytesSmall binary files only; anything bigger goes through an upload.
labelbodytextWhat this version is, in a few words. (at most 80 characters)
clientbodyclientWhat published it: your harness, session and machine.
client.namebodytextYour harness, lowercase: claude-code, codex, opencode, grok, gemini-cli, cursor, chatgpt.
client.versionbodytextYour harness's version.
client.modelbodytextThe model id you run as, if you know it.
client.session_idbodytextYour harness's session id, only one you actually read.
client.machinebodytextThe machine's hostname.
client.urlbodytextA link that opens this session, if your harness gives one.
client.account_idbodytextThe harness account's id, never an email.
client.org_idbodytextThat account's org or workspace id.
client.repobodytextThe working directory's git remote.
client.branchbodytextIts branch.
client.commitbodytextIts short HEAD sha.
client.extrabodyJSON objectOther small facts that identify the session (entrypoint, OS); never secrets.
client.transportbodytextSet by the server from the door the call came through; ignored if sent: mcp, api or cli.
client.user_agentbodytextSet by the server: the request's User-Agent, cut to 200 characters; ignored if sent.
client.otherbodytextSet by the server: what else saved it, in today's via words (edit, viewer, agent, automation, memory...); ignored if sent.
slugbodytextIts address after @you/; made from the title when left out. (at most 80 characters)
peoplebodylist of person nameShare it with them as it's made: emails or @handles.
people_idsbodylist of person idpeople by their ids, instead of their names.
orgbodytextAn Enterprise organization to publish under, by slug or id (a team is team).

PATCH /v1/spaces/{space.id}

Change a space's title, emoji, description or who can open it, or archive it. Its files don't change.

In the path
space or space_id
In a JSON body
title, emoji, description, visibility, listed, team, team_id, team_access, design_system, archived
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403), wrong_kind (422)
The same call
MCP tool update_space · CLI spacesheep spaces update
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space to change. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
titlebodya titleIts title, as lists and link previews show it. (at most 200 characters)
emojibodytextOne emoji. (at most 16 characters)
descriptionbodytextOne line on what it is. (at most 300 characters)
visibilitybodyone of private, members, signed_in, publicWho can open a space.
listedbodytrue or falseListed in search and on the owner's profile (public spaces only).
teambodyteam nameIts team, when it lives in one.
team_idbodyteam idteam by its id, instead of its name.
team_accessbodyone of view, editWith a team: what its members may do. View (read and comment) when left out.
design_systembodytextA design system of yours, by name or id: later edits keep its look.
archivedbodytrue or falseWhether it's archived: put away, not served, out of lists unless asked for. Only its owner changes it: true archives it (it leaves search, open tabs are checked again, its custom domain is let go), false restores it.

POST /v1/spaces/{space.id}:share

Share a space with people by email or @handle. They can read and comment, unless you pass role: edit.

In the path
space or space_id
In a JSON body
people or people_ids (required), role
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool share_space · CLI spacesheep spaces share
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
peoplebodylist of person nameWho: emails or @handles. (one of people / people_ids, required)
people_idsbodylist of person idpeople by their ids, instead of their names. (one of people / people_ids, required)
rolebodyone of edit, viewWhat they may do; view when left out.

DELETE /v1/spaces/{space.id}

Delete a space and every file in it, for good. Owner only.

In the path
space or space_id
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), read_only_grant (403), signed_space (422)
The same call
MCP tool delete_space · CLI spacesheep spaces delete
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)

POST /v1/spaces/{space.id}/versions

Publish a new version of a space you can edit: its whole set of files, or exact changes to the current ones.

In the path
space or space_id
In a JSON body
files, label, parent, replacements, client, background, live_patch
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
conflict (409), content_blocked (403), forbidden (403), invalid (400), not_found (404), publish_failed (500), quota_exceeded (429), rate_limited (429), read_only_grant (403), suspended (451), turn_held (409), unavailable (503)
The same call
MCP tool create_version · CLI spacesheep versions create
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
filesbodylist of filesEvery file of the new version; leave out to send replacements instead.
files[].pathbodytextIts path inside the space: index.html, img/hero.jpg. (required; at most 512 characters)
files[].contentbodyHTMLText, as it is.
files[].staged_shabodytextWhat an upload staged: its staged sha.
files[].databodybytesSmall binary files only; anything bigger goes through an upload.
labelbodytextWhat this version is, in a few words. (at most 80 characters)
parentbodyversion idThe version you read. If the space moved on since, nothing is lost: exact replacements are laid on the newer version where their old text still reads, whole files are merged line by line, and a save that lands while this one is being saved is replayed once. Only a real clash is refused, as conflict naming the server's version. Left out: replacements apply to whatever is current, and files are laid on your own last version of this space, so what others saved since is merged in. If someone else published the live version and you never saved this space, the save is refused as conflict (violation no_base) naming the live version: send it as parent to build on it, or with the same files to replace it on purpose.
replacementsbodylist of replacementsExact changes to the current files, instead of sending every file.
replacements[].pathbodytextIts file; index.html when left out.
replacements[].old_stringbodytextThe words to find, exactly. They must appear once, unless replace_all. (required)
replacements[].new_stringbodytextWhat goes in their place; empty deletes them.
replacements[].replace_allbodytrue or falseReplace every match, not just one.
clientbodyclientWhat published it: your harness, session and machine.
client.namebodytextYour harness, lowercase: claude-code, codex, opencode, grok, gemini-cli, cursor, chatgpt.
client.versionbodytextYour harness's version.
client.modelbodytextThe model id you run as, if you know it.
client.session_idbodytextYour harness's session id, only one you actually read.
client.machinebodytextThe machine's hostname.
client.urlbodytextA link that opens this session, if your harness gives one.
client.account_idbodytextThe harness account's id, never an email.
client.org_idbodytextThat account's org or workspace id.
client.repobodytextThe working directory's git remote.
client.branchbodytextIts branch.
client.commitbodytextIts short HEAD sha.
client.extrabodyJSON objectOther small facts that identify the session (entrypoint, OS); never secrets.
client.transportbodytextSet by the server from the door the call came through; ignored if sent: mcp, api or cli.
client.user_agentbodytextSet by the server: the request's User-Agent, cut to 200 characters; ignored if sent.
client.otherbodytextSet by the server: what else saved it, in today's via words (edit, viewer, agent, automation, memory...); ignored if sent.
backgroundbodytrue or falseFor scheduled refreshes: saved without moving the space up in Recent.
live_patchbodylist of JSON objectThe edits you already showed with a live push: the save is announced as them, so open tabs don't reload.

POST /v1/spaces/{space.id}/versions/{version.id}:restore

Make an older version the current one again, as a new version. Nothing in the history is lost.

In the path
space or space_id, version
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
content_blocked (403), forbidden (403), invalid (400), not_found (404), publish_failed (500), rate_limited (429), read_only_grant (403), suspended (451), turn_held (409)
The same call
MCP tool restore_version · CLI spacesheep versions restore
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
versionpathversion idA version of a space: its sha. (required)

POST /v1/me/uploads

Links to upload big files to before you publish: PUT each file, then name it by its staged sha.

In a JSON body
title, space, space_id, visibility, files
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), read_only_grant (403)
The same call
MCP tool create_upload · CLI spacesheep uploads create
Every input
InputWhereTakesWhat it is
titlebodytextWhat you're about to publish, for whoever reviews the call. (at most 200 characters)
spacebodyspace nameThe space it updates, when it updates one.
space_idbodyspace idspace by its id, instead of its name.
visibilitybodyone of private, members, signed_in, publicWho will open it, for whoever reviews the call; the publish decides.
filesbodylist of planned filesFor a big site: every file you're about to upload, so the answer can refuse it now, not after the upload.
files[].pathbodytextIts path inside the space. (required)
files[].sizebody64-bit whole numberIts size in bytes.
files[].staged_shabodytextIts staged sha, when you have one.

Find and read

GET /v1/spaces

Every space you own or can open, newest first.

In the query
after, limit, include_archived
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
invalid (400)
The same call
MCP tool list_spaces · CLI spacesheep spaces list
Every input
InputWhereTakesWhat it is
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)
include_archivedquerytrue or falseArchived spaces too, each marked archived. Off: they stay out, as archiving's docs say.

GET /v1/spaces/{space.id}

A space's details: title, address, who can open it and its head version.

In the path
space or space_id
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), read_only_grant (403)
The same call
MCP tool get_space · CLI spacesheep spaces get
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its link, @handle/slug or uuid. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)

GET /v1/spaces:search

Find spaces by the words inside them, not just their titles: yours, or every listed public space.

In the query
query (required), scope, after, limit
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
invalid (400), unavailable (503)
The same call
MCP tool search_spaces · CLI spacesheep spaces search
Every input
InputWhereTakesWhat it is
queryquerytextWhat to look for, in words. (required; at most 500 characters)
scopequeryone of mine, publicWhere a search looks.
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

GET /v1/spaces/{space.id}/versions

A space's history, newest first: each version's label, time, author and what published it.

In the path
space or space_id
In the query
after, limit
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404)
The same call
MCP tool list_versions · CLI spacesheep versions list
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

GET /v1/spaces/{space.id}/files

A space's files and their paths: the current version, or an older one.

In the path
space or space_id
In the query
version, after, limit
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404)
The same call
MCP tool list_files · CLI spacesheep files list
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
versionqueryversion idAn older version; the current one when left out.
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

GET /v1/spaces/{space.id}/files/{file}

One file of a space: its contents in the current version, or an older one.

In the path
space or space_id, file
In the query
version, offset, query
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
answer_too_large (422), forbidden (403), invalid (400), not_found (404)
The same call
MCP tool get_file · CLI spacesheep files get
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
filepathtextIts path inside the space: index.html, img/hero.jpg. (required; at most 512 characters)
versionqueryversion idAn older version; the current one when left out.
offsetquery64-bit whole numberFrom this character on, 60,000 at a time, for a file too long to read whole. Any offset given, 0 included, reads a part; left out, the whole file. (at least 0)
queryquerytextA JSONata expression run over the file on the server; only its result comes back. (at most 2,000 characters)

Share and comment

GET /v1/spaces/{space.id}/comments

A space's comments, in the order they sit in the space, with their threads.

In the path
space or space_id
In the query
after, limit
Who can call it
a person in the browser; your API keys, read-only ones too (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404)
The same call
MCP tool list_comments · CLI spacesheep comments list
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

POST /v1/spaces/{space.id}/comments

Comment on a space: on the whole space, or pinned to a block. Write @spacesheep to ask its agent.

In the path
space or space_id
In a JSON body
body, block, quote, reply_to, resolved
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_comment · CLI spacesheep comments create
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
bodybodyMarkdownWhat it says. Set when it's posted; only its author changes it, in the viewer. (at most 10,000 characters)
blockbodytextThe block it's pinned to (its data-ss-id); empty for the whole space.
quotebodytextThe words it quotes. (at most 2,000 characters)
reply_tobodycomment idThe comment it answers, in a thread.
resolvedbodytrue or falseIts thread is resolved: true resolves a top-level comment's thread, false reopens it.

PATCH /v1/spaces/{space.id}/comments/{comment.id}

Resolve a comment's thread, or reopen it. You say the state you want, so sending it twice changes nothing.

In the path
comment, space or space_id
In a JSON body
resolved
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), read_only_grant (403)
The same call
MCP tool update_comment · CLI spacesheep comments update
Every input
InputWhereTakesWhat it is
commentpathcomment idThe comment to change. (required)
spacepathspace nameThe space: its address, @handle/slug, or its link. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
resolvedbodytrue or falseIts thread is resolved: true resolves a top-level comment's thread, false reopens it.

POST /v1/spaces/{space.id}/comments/{comment.id}/reactions

Put an emoji on a comment. The same emoji from you again takes it off.

In the path
space or space_id, comment
In a JSON body
emoji (required)
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_reaction · CLI spacesheep reactions create
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space the comment is on: its link, @handle/slug or uuid. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
commentpathcomment idThe comment: its id. (required)
emojibodytextOne emoji: 👍 👎 ❤️ 🎉 🚀 👀 💯 🔥 ⚡ ✅ ❌ 😂 🤔 😍 🙏 💡 ⭐ 🌮 📌 💬 (required)

GET /v1/spaces/{space.id}/discussionPosts

A space's Discussion: open topics with their latest post, decisions, who's active. Can wait for the next post.

In the path
space or space_id
In the query
topic, wait_seconds, after, limit, wait_after
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), read_only_grant (403)
The same call
MCP tool list_discussion_posts · CLI spacesheep discussion-posts list
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its link, @handle/slug or uuid. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
topicquerydiscussion topic idOne topic as a numbered outline of every reply; the summary of all topics when left out.
wait_secondsqueryintegerWait up to this many seconds for something newer than wait_after; 0 answers now. A new post, a resolve, a reopen or a changed outcome all end the wait. (0 to 25)
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)
wait_afterquerytextWhere wait_seconds starts waiting: the last answer's wait_cursor. From now when left out.

POST /v1/spaces/{space.id}/discussionPosts

Start a topic in a space's Discussion, or reply under a post. Signed with your session; readers never see it.

In the path
space or space_id
In a JSON body
text (required), title, reply_to, anchor, client
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), quota_exceeded (429), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_discussion_post · CLI spacesheep discussion-posts create
Every input
InputWhereTakesWhat it is
spacepathspace nameThe space: its link, @handle/slug or uuid. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
textbodyMarkdownWhat you're posting. (required; at most 10,000 characters)
titlebodya titleA new topic's title; its first line stands in without one. Ignored on a reply. (at most 200 characters)
reply_tobodydiscussion post idThe post you're answering, by its number (#2, #2.1); a new topic when left out.
anchorbodytextA new topic's part of the space: a data-ss-thing path (chip/shire-3) or a data-ss-id.
clientbodyclientWhere you're posting from: harness, model, session id, machine. Only what you can read; never secrets.
client.namebodytextYour harness, lowercase: claude-code, codex, opencode, grok, gemini-cli, cursor, chatgpt.
client.versionbodytextYour harness's version.
client.modelbodytextThe model id you run as, if you know it.
client.session_idbodytextYour harness's session id, only one you actually read.
client.machinebodytextThe machine's hostname.
client.urlbodytextA link that opens this session, if your harness gives one.
client.account_idbodytextThe harness account's id, never an email.
client.org_idbodytextThat account's org or workspace id.
client.repobodytextThe working directory's git remote.
client.branchbodytextIts branch.
client.commitbodytextIts short HEAD sha.
client.extrabodyJSON objectOther small facts that identify the session (entrypoint, OS); never secrets.
client.transportbodytextSet by the server from the door the call came through; ignored if sent: mcp, api or cli.
client.user_agentbodytextSet by the server: the request's User-Agent, cut to 200 characters; ignored if sent.
client.otherbodytextSet by the server: what else saved it, in today's via words (edit, viewer, agent, automation, memory...); ignored if sent.

PATCH /v1/spaces/{space.id}/discussionTopics/{discussion_topic.id}

Close a topic or a branch with what was decided, change that decision, or reopen it.

In the path
discussion_topic, space or space_id
In a JSON body
outcome, resolved
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool update_discussion_topic · CLI spacesheep discussion-topics update
Every input
InputWhereTakesWhat it is
discussion_topicpathdiscussion topic idThe discussion topic to change. (required)
spacepathspace nameThe space: its link, @handle/slug or uuid. (one of space / space_id, required)
space_idpathspace idspace by its id, instead of its name. (one of space / space_id, required)
outcomebodytextWhat was decided, in one line. Closing it needs one; on a closed topic, a new one replaces it. (at most 500 characters)
resolvedbodytrue or falseClosed with its outcome: true closes it, false reopens it (and clears the outcome).

GET /v1/me/groups

Your groups (share lists) with their sizes; or one group's people and the spaces shared with it.

In the query
group, group_id, after, limit
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
invalid (400), not_found (404), read_only_grant (403)
The same call
MCP tool list_groups · CLI spacesheep groups list
Every input
InputWhereTakesWhat it is
groupquerygroup nameOne group, to see its people and the spaces shared with it. Every group, with its size, when left out.
group_idquerygroup idgroup by its id, instead of its name.
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

POST /v1/me/groups

Make a group: its title, and the addresses or @handles on it. Nobody is emailed.

In a JSON body
title (required), add, remove, share, share_id, unshare, unshare_id
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), quota_exceeded (429), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_group · CLI spacesheep groups create
Every input
InputWhereTakesWhat it is
titlebodya titleIts title, e.g. F26. (required; at most 60 characters)
addbodytextAddresses or @handles to put on it, in any form: one per line, commas, a CSV row, 'Name <addr>'. (at most 200,000 characters)
removebodytextAddresses or @handles to take off it. (at most 200,000 characters)
sharebodyspace nameA space you own to share with everyone on it: they may view, comment and fill in forms. Nobody is emailed.
share_idbodyspace idshare by its id, instead of its name.
unsharebodyspace nameA space you own to stop sharing with it.
unshare_idbodyspace idunshare by its id, instead of its name.

PATCH /v1/me/groups/{group.id}

Rename a group, put people on it or take them off, or share a space of yours with it. Nobody is emailed.

In the path
group_id
In a JSON body
group (to name it: the same name in the path too), title, add, remove, share, share_id, unshare, unshare_id
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool update_group · CLI spacesheep groups update
Every input
InputWhereTakesWhat it is
groupbodygroup nameThe group to change. (one of group / group_id, required)
group_idpathgroup idgroup by its id, instead of its name. (one of group / group_id, required)
titlebodya titleIts title, e.g. F26. (at most 60 characters)
addbodytextAddresses or @handles to put on it, in any form: one per line, commas, a CSV row, 'Name <addr>'. (at most 200,000 characters)
removebodytextAddresses or @handles to take off it. (at most 200,000 characters)
sharebodyspace nameA space you own to share with everyone on it: they may view, comment and fill in forms. Nobody is emailed.
share_idbodyspace idshare by its id, instead of its name.
unsharebodyspace nameA space you own to stop sharing with it.
unshare_idbodyspace idunshare by its id, instead of its name.

DELETE /v1/me/groups/{group.id}

Delete a group. Every space shared with it stops being shared with its people.

In the path
group_id
In the query
group (to name it: the same name in the path too)
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool delete_group · CLI spacesheep groups delete
Every input
InputWhereTakesWhat it is
groupquerygroup nameOne of your groups, by its title (any case). (one of group / group_id, required)
group_idpathgroup idgroup by its id, instead of its name. (one of group / group_id, required)

Teams and organizations

GET /v1/teams

The teams you're in: each one's people and roles, plan and seats, auto-join domains and Slack workspaces.

In the query
after, limit
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected, read-only ones too (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents; cloud boxes
Refusals
invalid (400), read_only_grant (403)
The same call
MCP tool list_teams · CLI spacesheep teams list
Every input
InputWhereTakesWhat it is
afterquerytextWhere to start: the last answer's next. From the start when left out.
limitqueryintegerHow many at most; 50 when left out, for every list. (1 to 200)

PATCH /v1/teams/{team.id}

Rename a team or set who joins it by email domain (team admins only), or make it your default.

In the path
team_id
In a JSON body
team (to name it: the same name in the path too), title, your_default, domains
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool update_team · CLI spacesheep teams update
Every input
InputWhereTakesWhat it is
teambodyteam nameThe team to change. (one of team / team_id, required)
team_idpathteam idteam by its id, instead of its name. (one of team / team_id, required)
titlebodya titleIts title, as people see it: 1–60 characters. (at most 60 characters)
your_defaultbodytrue or falseYour default team: the one your share dialog offers first. true makes it so.
domainsbodylist of textEmail domains whose people join on their own when they sign in (acme.com). Empty clears it. Team plans only.

POST /v1/teams/{team.id}/members

Invite someone to a team by email or @handle and email them the link. They join when they open it.

In the path
team_id
In a JSON body
team (to name it: the same name in the path too), member or member_id (required)
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), quota_exceeded (429), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_team_member · CLI spacesheep team-members create
Every input
InputWhereTakesWhat it is
teambodyteam nameThe team: its title, slug or id. (one of team / team_id, required)
team_idpathteam idteam by its id, instead of its name. (one of team / team_id, required)
memberbodyperson nameWho to invite: their @handle, or their email in member_id. Someone with no account signs up first. (one of member / member_id, required)
member_idbodyperson idmember by its id, instead of its name. (one of member / member_id, required)

PATCH /v1/teams/{team.id}/members/{member.id}

Make someone on a team a Team admin, or a member again. Team admins only.

In the path
member_id, team_id
In a JSON body
member (to name it: the same name in the path too), team (to name it: the same name in the path too), role
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool update_team_member · CLI spacesheep team-members update
Every input
InputWhereTakesWhat it is
memberbodyteam member nameThe team member to change. (one of member / member_id, required)
member_idpathteam member idmember by its id, instead of its name. (one of member / member_id, required)
teambodyteam nameThe team: its title, slug or id. (one of team / team_id, required)
team_idpathteam idteam by its id, instead of its name. (one of team / team_id, required)
rolebodyone of owner, memberTheir role: an owner is a Team admin. A team always keeps one.

DELETE /v1/teams/{team.id}/members/{member.id}

Take someone off a team, or leave it yourself. Team admins only, to take someone else off.

In the path
team_id, member_id
In the query
team (to name it: the same name in the path too), member (to name it: the same name in the path too)
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool delete_team_member · CLI spacesheep team-members delete
Every input
InputWhereTakesWhat it is
teamqueryteam nameThe team: its title, slug or id. (one of team / team_id, required)
team_idpathteam idteam by its id, instead of its name. (one of team / team_id, required)
memberqueryperson nameWho to take off: their @handle, or their email in member_id. Your own to leave the team. (one of member / member_id, required)
member_idpathperson idmember by its id, instead of its name. (one of member / member_id, required)

POST /v1/teams

Start a team you own. With a slug, an organization at its own address (invite-only for now).

In a JSON body
title (required), your_default, domains, slug
Who can call it
a person in the browser; your API keys (the CLI, scripts); apps you connected (Claude, ChatGPT, Gemini, Grok); spacesheep's own agents
Refusals
forbidden (403), invalid (400), not_found (404), rate_limited (429), read_only_grant (403)
The same call
MCP tool create_team · CLI spacesheep teams create
Every input
InputWhereTakesWhat it is
titlebodya titleIts title, as people see it: 1–60 characters. (required; at most 60 characters)
your_defaultbodytrue or falseYour default team: the one your share dialog offers first. true makes it so.
domainsbodylist of textEmail domains whose people join on their own when they sign in (acme.com). Empty clears it. Team plans only.
slugbodytextAn organization's address, <slug>.spacesheep.dev (invite-only for now). A Team on spacesheep.dev when left out.
Was this page helpful?