Current API Notes
April 18, 2026 · View on GitHub
This document covers live API features that are easy to miss in the README.
It is based on the current code in src/api/routes/ and related modules.
Route Count
Tandem currently exposes 302 HTTP routes across the API and security route
modules.
New in v0.75.0
POST /behavior/recompile
Forces an on-demand recompile of the per-user behavioural profile from the
current ~/.tandem/behavior/raw/*.jsonl stream and returns the freshly-
computed profile. Useful after a long typing session when you want the
agent's humanized click/type to incorporate new rhythm data without
restarting Tandem.
Response shape:
{
"ok": true,
"profile": {
"typingSpeed": { "meanWpm": 62, "variance": 38 },
"mouseMovement": { "curveBias": "ease-in-out", "averageSpeedPxPerMs": 1.2 },
"source": "compiled",
"samples": 142,
"lastCompiledAt": 1776519584976
}
}
The source discriminator lets callers tell at a glance whether the profile
reflects real user data (compiled) or still-at-floor fallback values
(default-insufficient = data exists but below the 100-sample floor;
default = no data at all). Rate-limited at 10 requests / minute.
The behavioural profile also auto-compiles on every Tandem boot. You only
need /behavior/recompile if you want freshly-typed data to flow into the
agent within the same session.
Interactive approval on security-weakening endpoints
The following endpoints now require an interactive user approval via the
Wingman panel when the requested change would weaken Tandem's security
posture. Tightening and no-op changes still pass through without friction.
Rejected requests return 403 { rejected: true }.
POST /security/guardian/mode— lowering the per-domain guardian mode (e.g.,balanced → permissive) requires approval.POST /security/domains/:domain/trust— raising the trust level for a domain requires approval.POST /security/outbound/whitelist— always requires approval (adding a whitelist pair is inherently a bypass).POST /security/injection-override— requires approval for agent / MCP callers. Shell-initiated calls (after the scanner's own double- confirmation modal) pass through via theX-Tandem-Shell-Initiated: 1header.
Approval tasks appear in Wingman's Activity panel and Chat panel with Approve / Reject buttons; clicking either dismisses both.
POST /tabs/open
Opens a new tab.
Important request fields
urloptional, defaults toabout:blankgroupIdoptionalsourceoptional:robin,kees, orwingmanfocusoptional boolean, defaults totrueinheritSessionFromoptional string tab id
inheritSessionFrom
If inheritSessionFrom points at an existing source tab, Tandem will:
- open the destination tab
- dump IndexedDB data from the source tab
- restore that IndexedDB data into the new tab
- reload the destination page
This is intended for sites that keep login state in IndexedDB instead of cookies or localStorage.
If the source tab does not exist, Tandem still opens the tab and ignores the inheritance request.
X-Tab-Id Background Targeting
Use X-Tab-Id: <tabId> when you want to inspect or evaluate a background tab
without focusing it first.
Current route support
GET /snapshotGET /page-contentGET /page-htmlPOST /execute-jsPOST /waitGET /linksGET /forms
POST /execute-js also still accepts tabId in the JSON body, but the header
is the preferred targeting mechanism.
Snapshot refs
Snapshot refs now remember which tab produced them, so /snapshot/text,
/snapshot/click, and /snapshot/fill keep resolving against that source tab
instead of whichever tab happens to be active later.
Injection Scanner Middleware
The injection scanner sits on agent-facing content routes:
GET /page-contentGET /page-htmlGET /snapshotGET /snapshot/textPOST /execute-js
It scans returned text and HTML for prompt-injection patterns.
Outcomes
- score
< 30: response passes unchanged - score
30-69: response passes withinjectionWarnings - score
>= 70: response is blocked unless the domain has an active override
injectionWarnings
Warning responses add:
{
"injectionWarnings": {
"riskScore": 42,
"findingCount": 2,
"summary": "…",
"findings": [
{
"id": "ignore_previous",
"severity": "critical",
"category": "instruction_override",
"description": "Attempts to override prior instructions",
"matchedText": "ignore previous instructions"
}
]
}
}
Blocked responses do not include the original page payload.
POST /security/injection-override
Temporarily bypasses prompt-injection blocking for one domain.
Request body
{ "domain": "example.com" }
Behavior
- grants a 5-minute override
- intended for explicit user confirmation after a block event
GET /config/openclaw-connect
Builds the signed OpenClaw gateway connect payload used by Tandem's in-app Wingman chat.
Query parameters
noncerequired
Response
Returns:
{ "params": { "...": "signed connect payload" } }
Error conditions
400ifnonceis missing404if~/.openclaw/openclaw.jsonis missing
GET /network/har
Exports the current network log in HAR format.
Query parameters
limitoptional, defaults to100domainoptional filter
Behavior
- returns HAR JSON
- sets
Content-Dispositionso the response downloads as a.harfile
Google Photos Integration
Routes:
GET /integrations/google-photos/statusPOST /integrations/google-photos/configPOST /integrations/google-photos/connectPOST /integrations/google-photos/disconnectGET /google-photos/oauth/callback
These endpoints support local OAuth configuration, connect or disconnect, and the callback flow used for screenshot uploads.
Preview System
Routes:
GET /previewsPOST /previewPUT /preview/:idGET /preview/:id/metaGET /preview/:idDELETE /preview/:idGET /previews/index
Behavior
- previews are stored under
~/.tandem/previews/ POST /previewcreates a preview and opens it in a new tab by defaultPUT /preview/:idupdates it and increments its versionGET /preview/:idserves the preview HTML with injected live reload polling- preview pages are public routes so they can be opened directly in a browser tab
GET /active-tab/context
Returns a compact agent-oriented view of the active browsing state.
Includes
- readiness state
- active tab id, URL, and title
- viewport and scroll data when available
- a short text excerpt from the active page
- all open tabs with active-state markers
Use this when the agent needs context without separately polling /status and
content endpoints.