API Reference

Every public JARVIS API endpoint — methods, paths, parameters, responses, and errors.

All endpoints are relative to https://jarvis.spacekeep.dev and speak JSON.

Conventions

  • Auth is shown per endpoint: None, Session, or Key — Key also accepts a session.

  • Length limits return 400 when exceeded.

  • Requesting an identifier that belongs to another account returns 404, not 403, so ids cannot be probed.

  • Timestamps are ISO 8601 UTC strings.

Error shape

{ "error": "Message content is required." }
Status Meaning
400 Invalid body, missing field, or a value over its limit
401 Missing, invalid, or revoked credential
403 The account is restricted — see Global Enforcement
404 No such resource for this account
409 Already exists
429 Rate limit reached
500 Server-side failure
503 Access could not be verified right now
504 The reply took too long

Chat

POST /api/jarvis/chat — Key or Session

Ask JARVIS a question. Returns a complete reply.

Request

Field Type Required Notes
message string Yes 1–8,000 characters
conversationId string No Continue an existing conversation for context
messages array No Prior turns, for stateless calls only

Response

Field Type Notes
reply string JARVIS's answer, in Markdown
conversationId string The conversation the exchange belongs to
sources array Present only when a search ran — see below
toolRun object Present only when a capability actually ran
policyDenied boolean Present only when a policy denial replaced the reply
nameSuggestion object Present only when JARVIS detected a preferred-name statement

A source object has title, url, domain, snippet, and favicon.

A toolRun object has state (completed or error), a short caption, and a steps array of { label, state }.

Responses also carry internal metadata fields that are not part of this public contract and may change at any time. Depend only on the fields documented above.

curl -s https://jarvis.spacekeep.dev/api/jarvis/chat \
  -H "Authorization: Bearer $JARVIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"What is the latest Node.js version? Search this on Google."}'
{
  "reply": "Node.js 24 is the current release line…",
  "conversationId": "0f3a9c1e-…",
  "toolRun": {
    "state": "completed",
    "caption": "Search completed — 5 results.",
    "steps": [
      { "label": "Thinking", "state": "done" },
      { "label": "Searching the web", "state": "done" },
      { "label": "Reviewing results", "state": "done" },
      { "label": "Preparing response", "state": "done" }
    ]
  },
  "sources": [
    {
      "title": "Node.js — Official Release",
      "url": "https://nodejs.org/en/blog/release/v24.0.0",
      "domain": "nodejs.org",
      "snippet": "…",
      "favicon": "…"
    }
  ]
}

Errors

Status Cause
400 Invalid JSON, empty message, or message over 8,000 characters
401 No credential, or Invalid API key.
404 conversationId does not exist for this account
429 Over 40 requests per minute
503 Access could not be verified
504 The reply took too long — retry with a shorter prompt

Conversations

A conversation object is { id, title, createdAt, updatedAt }. A message object is { id, role, content, policyDenied, createdAt }, where role is user or assistant.

Only conversations that contain at least one message are listed.

GET /api/conversations — Key or Session

Recent conversations, newest first. Up to 100 are returned.

Query Notes
q Search titles and message content. Up to 80 characters
{ "conversations": [{ "id": "0f3a…", "title": "Node.js release notes", "createdAt": "…", "updatedAt": "…" }] }

400 if q is longer than 80 characters.

POST /api/conversations — Key or Session

Create a conversation.

Body Type Notes
title string Optional, up to 80 characters. Defaults to New conversation

Returns 201 with { "conversation": { … } }. 400 if title is over 80 characters.

GET /api/conversations/:id — Key or Session

Returns { "conversation": { … }, "messages": [ … ] }.

404 if the conversation does not exist for this account.

PATCH /api/conversations/:id — Key or Session

Rename a conversation.

Body Type Required Notes
title string Yes 1–80 characters, single line

Returns { "conversation": { … } }.

400 if title is missing, empty, over 80 characters, or contains control characters. 404 if the conversation does not exist for this account.

DELETE /api/conversations/:id — Key or Session

Deletes the conversation and its messages. Returns { "ok": true }.

404 if the conversation does not exist for this account.

POST /api/conversations/:id/messages — Key or Session

Store a user-authored message in a conversation.

Body Type Required Notes
content string Yes 1–8,000 characters

Returns 201 with { "message": { … }, "conversation": { … } }.

400 if content is missing or over 8,000 characters. 404 if the conversation does not exist for this account.


Tasks

A task object is { id, title, status, createdBy, createdAt, updatedAt, completedAt }, where status is open or done and createdBy is user or assistant.

GET /api/tasks — Key or Session

Query Notes
status open or done. Omit for all
{ "tasks": [{ "id": "…", "title": "Renew the domain", "status": "open", "createdBy": "user", "createdAt": "…", "updatedAt": "…", "completedAt": null }] }

POST /api/tasks — Key or Session

Body Type Required Notes
title string Yes 1–200 characters

Returns 201 with { "task": { … } }. 400 if the title is missing or outside the range.

PATCH /api/tasks/:id — Key or Session

Update a task. Send title, status, or both.

Body Type Notes
title string 1–200 characters
status string open or done

Returns { "task": { … } }. Setting done records completedAt; setting open clears it, so completion is reversible.

400 if nothing valid was sent or status is not open or done. 404 if the task does not exist for this account.

DELETE /api/tasks/:id — Key or Session

Returns { "ok": true }. 404 if the task does not exist for this account.


Memories

Session-only. A memory object is { id, type, content, fromConversation, createdAt, updatedAt }, where type is user, preference, or project.

GET /api/memories — Session

Query Notes
type user, preference, or project. Omit for all
{ "memories": [{ "id": "…", "type": "preference", "content": "Prefers TypeScript over JavaScript", "fromConversation": true, "createdAt": "…", "updatedAt": "…" }] }

fromConversation is a hint that the memory was saved from a conversation.

PATCH /api/memories/:id — Session

Edit a memory in place.

Body Type Required Notes
content string Yes 4–500 characters, single line

The category is re-derived from the new text. Returns { "memory": { … } }.

400 if content is missing or outside the range. 404 if the memory does not exist for this account.

DELETE /api/memories/:id — Session

Returns { "ok": true }. 404 if the memory does not exist for this account.


Web

Session-only.

GET /api/web — Session

Web search status and lookup history.

{
  "searchConfigured": true,
  "enabled": true,
  "lookups": [
    { "id": "…", "query": "Node.js release notes", "status": "ok", "resultCount": 5, "error": null, "conversationId": "0f3a…", "createdAt": "…" }
  ]
}

status is ok or error. searchConfigured reports whether search is available on the deployment — it never reveals configuration.

DELETE /api/web — Session

Clears the lookup history. Returns { "ok": true, "cleared": 12 }.

The preference and stored conversations are untouched.


Keys

Session-only. A key object is { id, name, prefix, createdAt, lastUsedAt, revokedAt }.

GET /api/keys — Session

Returns { "keys": [ … ] }. Key material is never included.

POST /api/keys — Session

Create a key.

Body Type Required Notes
name string No Up to 40 characters. Defaults to Default key
{
  "key": "jrv_<your-new-key>",
  "id": "…",
  "name": "ci",
  "prefix": "jrv_XXXXXX",
  "createdAt": "…"
}

429 after 10 creations per minute.

DELETE /api/keys/:id — Session

Revokes a key. Returns { "ok": true }. Takes effect on that key's next request.

404 if the key does not exist for this account.


Account

GET /api/auth/session — None

The current session.

{ "user": { "id": "…", "email": "you@domain.com", "displayName": "Sam", "preferredLanguage": "auto", "memoryEnabled": true, "webSearchEnabled": true } }

Returns { "user": null } when signed out. Returns 403 if the account is restricted and 503 if access cannot be verified.

POST /api/auth/logout — Session

Ends the current session. Returns { "ok": true }.

POST /api/auth/register — None

Body Type Required Notes
email string Yes Valid address, up to 254 characters
password string Yes 8–128 characters
confirmPassword string Yes Must match password
displayName string No Up to 64 characters

Returns 201 with { "user": { "id": "…", "email": "…" } } and sets a session cookie.

409 if the address already has an account. 403 if the address is restricted.

POST /api/auth/login — None

Body Type Required
email string Yes
password string Yes

Returns { "user": { "id": "…", "email": "…" } } and sets a session cookie.

401 with the same message for an unknown address and a wrong password. 403 if the account is restricted.

POST /api/auth/forgot — None

Body Type Required
email string Yes

Always returns { "message": "If an account exists for that address, a reset link is on its way." } — whether or not the address is registered. 503 if the email could not be handed off for delivery.

POST /api/auth/reset — None

Body Type Required Notes
token string Yes From the reset email
password string Yes 8–128 characters
confirmPassword string Yes Must match

Returns { "ok": true }. On success every session for the account is ended and outstanding reset links are invalidated.

400 if the token is unknown, already used, or expired (30 minutes).

PATCH /api/auth/profile — Session

Update your own preferences. Send any subset of fields.

Field Type Notes
displayName string Up to 64 characters
preferredLanguage string auto, en, de, or it
memoryEnabled boolean Store and use memories
webSearchEnabled boolean Allow web searches
displayNameChangePromptDisabled boolean Stop offering name-change prompts

Returns the updated { "user": { … } }.

400 if a field has an invalid value or nothing valid was sent.

GET /api/auth/oauth/:provider — None

Starts a provider sign-in. :provider is google or github. Responds with a redirect to the provider, then returns to /api/auth/oauth/:provider/callback.

Errors are returned as a redirect back to the sign-in page with a code: config, state, denied, provider, email, or server. See Sign-in errors.


Health

GET /api/health — None

Service status. See Health.