Skip to content

REST API

Everything the web UI does goes through the same REST API, and a Service Token is all your own code needs to reach it. A CI job that opens a workspace, a script that bulk-loads prompts, a local agent handing a long task to a hosted one — all the same surface.

The interactive reference is on your instance

Section titled “The interactive reference is on your instance”

Your own NAP serves it:

https://<your-nap-host>/api/docs

Signed in, ⌘K → API Docs goes straight there. The machine-readable document sits beside it at /api/docs/openapi.json.

It isn’t mirrored here on purpose: what your instance serves is generated from the control plane you are actually running, so it matches your version rather than ours.

Create a token in the UI — ⌘K → Service Tokens (route /integration/tokens) → Create Service Token. It is shown once, so copy it then.

Every request carries it:

Authorization: Bearer <token>

Paths are relative to your host, so GET $NAP_BASE_URL/api/workspaces lists workspaces.

One convention worth knowing before it bites: URL-encode query parameters that carry a path. Encode the whole value — slashes inside it are literal, not separators. A raw CJK or slashed value gets a 400 or lands somewhere else.

There is deliberately no exec endpoint for service tokens. Work goes to the agent as a prompt, and the agent has its full toolset behind it — bash, file editing, everything it has in the UI:

Terminal window
BASE="${NAP_BASE_URL:?}"
NAP_WS="<workspace-id>"
# Start the turn. async returns 202 immediately with a session id.
SID=$(curl -s -X POST "$BASE/api/workspaces/$NAP_WS/chat" \
-H "Authorization: Bearer $NAP_TOKEN" -H "Content-Type: application/json" \
-d '{"message":"List the files in the repo and summarize the README","mode":"async","source":"api"}' \
| jq -r .session_id)
# Poll until the session is done: no turn running, no agent calls outstanding.
while :; do
S=$(curl -s "$BASE/api/workspaces/$NAP_WS/sessions/$SID" -H "Authorization: Bearer $NAP_TOKEN")
[ "$(echo "$S" | jq -r .chat_status)" != "agent" ] \
&& [ "$(echo "$S" | jq -r '.pending_agent_calls // 0')" = "0" ] && break
sleep 3
done
# Then read the transcript.
curl -s "$BASE/api/workspaces/$NAP_WS/messages?session_id=$SID" \
-H "Authorization: Bearer $NAP_TOKEN" | jq .

Turns can also stream, if you’d rather watch it work than wait for it.

A session is done when chat_status is not agent and pending_agent_calls is 0. The second half is easy to miss.

One request starts one turn, but the session may run more turns than you started. An agent that hands work to other agents can end its turn while they’re still running, with a reply that amounts to “dispatched, waiting”. When a called agent finishes, the platform posts its result into the session and the agent takes a further turn on its own. In between, the session reads idle with pending_agent_calls above zero, and its last reply isn’t the answer yet.

ModeWhat to do
asyncPoll GET /api/workspaces/{id}/sessions/{sessionId} until both conditions hold, as in the loop above.
syncThe response carries pending_agent_calls. At 0, final_message is the answer. Above 0 it’s interim — poll the session, then read the messages.
streamThe stream closes at the end of the first turn. Read the session afterwards and poll if calls are outstanding.

Delivered results show up in the transcript as user messages wrapped in <agent-sys>…</agent-sys>, whose first line begins [Automated delivery of call_agent results. Nobody typed them; the answer is the last assistant message.

Results are posted back only into sessions started with source api or web. In sessions started by a schedule or a chat connector the agent waits for its calls inside the one turn, and pending_agent_calls stays 0.

Where things are when they aren’t where you’d look first:

You want toGo to
Have the agent do something — run a task, edit files, answer about its workPOST /api/workspaces/{id}/chat
Read, write or list files in the workspacethe agent-files resource
Reach the shared /mnt/afs volumethe agent-afs-files resource — a different mount
Create and configure a workspacePOST /api/workspaces, then PUT /api/workspaces/{id}/config
Bulk-manage prompts, templates or skillsthe prompts, templates, skills resources

Rather than reading operation lists yourself, hand them to an agent: the nap-api skill is generated from this same spec, and it’s what lets a local agent drive NAP.