GraphQL
An Apollo Server (Federation subgraph) is mounted at/api/graphql through a Next.js route handler. Outside production — or when APOLLO_SANDBOX=true — introspection and the Apollo sandbox are enabled, so opening /api/graphql in a browser lets you explore the schema.
The SDL lives in schemas/**/*.graphql, one file per domain, and is bundled into the app by scripts/prebuild-schema.ts. Resolvers are dependency-injected factories under src/graphql/resolvers/.
Subscriptions are served over a separate WebSocket listener rather than the HTTP route:
Browser clients authenticate with a Better Auth cookie. Native clients and enrolled agents send their bearer credential in the
authorization connection parameter. API clients send X-API-Key as a header or connection parameter. The server resolves exactly one typed principal — user, API key, or agent — before execution. The app also rewrites /graphql on the HTTP origin to the WebSocket listener, so a browser and a reverse proxy can reach subscriptions on a single origin.
Every query, mutation, and type is documented in the GraphQL API tab, generated from that schema.
Build clients use buildRunAgents(buildId:) to discover eligible target Macs, optionally pass agentId to inspectBuildRunDestinations, and pass targetAgentId with RunBuildInput. Omitting either agent field preserves the original build-agent behavior. Deployment results expose the target agent and optional artifact-transfer status and progress.
Shared server URLs
ServerUrlKind is LOCAL, REMOTE, or PROXY. Use serverUrlSettings to read detected and effective origins, overrides, Proxy, and defaults; saveServerUrlSettings saves them; serverUrlSettingsChanged notifies clients to refetch. Telemetry override fields remain deprecated delegates to this shared service.
StartBuildInput.serverUrlKind is optional. Builds and coverage builds snapshot the resolved bases and choice; rebuilds retain the kind and resolve current settings. buildArtifactLinks returns signed download and selected manifest URLs. Device enrollment and OTA routes carry serverUrlKind through follow-up URLs, resolved server-side against configured settings.
SSE responses include endpointPath, localUrl, remoteUrl, and nullable proxyUrl; publicUrl remains for compatibility. See Server URLs and the script contract.
MCP catalog and preset portability
The web and iOS apps use the same GraphQL operations to export tool definitions, share presets, and review imports:
Exports return
filename, contentType, and the document’s content. Catalog exports can be partial when an external server cannot be discovered; check the exported availability information before using them as an inventory.
McpToolPreset.tools field contains { source, name, serverId, serverName }. Built-ins use source: BUILTIN and their ordinary name; external references use source: EXTERNAL, a local serverId, and the raw upstream tool name. The legacy toolNames output contains only built-in names.
Use McpToolPresetInput.tools for complete mixed membership. Do not send it together with toolNames. Older clients can continue editing built-in-only presets with toolNames. A legacy update to a mixed preset is rejected with an upgrade message so external selections cannot be lost.
Portable documents use format: "aide.mcp-presets.export", schemaVersion: 1, and an array of presets. External selections use a document-local serverKey, not a local server ID or an advertised MCP alias. See the portable JSON example. Documents are limited to 2 MiB and 100 presets.
McpToolPresetImportInput.document is the JSON document serialized as a string. Optional decisions contain an entry index, an action (CREATE, REPLACE, or SKIP), and optional name and targetId. Optional serverMappings associate { serverKey, serverId } with an already configured external server. Import never creates servers or credentials.
input with the preview’s token as previewToken:
REPLACE keeps the target preset’s ID.
Agent build-transfer routes
Cross-agent app deployment uses REST routes under/api/agent/build-artifact-transfers/{transferId}. They support transfer status and metadata, HEAD offset inspection, sequential PATCH upload chunks, completion, and ranged download. These endpoints accept only the enrolled source or target agent assigned to that transfer; browser sessions and general API keys cannot substitute for that identity. Their payloads are intentionally small or ranged so reverse proxies never receive a whole large .app archive in one request.
A placeholder health query verifies database connectivity. It returns "ok" when the database is reachable, and "degraded" otherwise:
REST endpoints
Codebases
Read-only access to the codebase checkouts registered across every enrolled agent. These endpoints require a Better Auth session. API keys and agent credentials are not accepted.id, path, observedOrigin, branch, headSha, upstream, ahead, behind, syncState, availability, statusError, the lastCheckedAt / lastFetchedAt timestamps, an optional branch listing, plus nested repository, agent, and activeJob objects.
Errors use a consistent envelope — { "error": { "code", "message" } }:
Telemetry ingestion
Applications under test post their own logs and analytics events here. These endpoints are unauthenticated by design — they are meant to be reachable from a device or simulator.
Both ingestion endpoints accept either a single record or an atomic
{ "items": [...] } batch of at most 500 records, with the request body capped at 2 MiB.
A
202 is not a failure. It means the server understood the payload and
deliberately dropped it because collection is turned off, so a client can keep
posting without special-casing the disabled state.PAYLOAD_TOO_LARGE beyond that.
Direct export calls may omit locale and timeZone. When supplied, locale must be one of the dashboard’s supported locales and timeZone must be a valid IANA time-zone identifier; unrecognized values return 400 instead of reaching the formatter.
Crash and dSYM uploads
Apps post crash reports and CI posts debug symbols here. See Crashes and dSYMs for full examples. GitHub Actions workflows can use the Upload dSYMs action, which runs the resumable upload.
Anonymous crash uploads are limited to 30 a minute per address and answer
202 without storing anything while crash collection is off. A bad credential is refused with 401 rather than treated as anonymous.
APNs device registration
The body carries
clientRegistrationId, token, tokenEncoding (HEX or BASE64), topic, environment (SANDBOX or PRODUCTION), supportedPushTypes, and displayName. A new registration returns 201, refreshing an existing one returns 200. The body is capped at 32 KiB and each source IP is limited to 120 requests per minute, after which it gets 429. See Push notifications.
Notification device registration
The body carries
clientRegistrationId, token, tokenEncoding, topic, environment, and displayName, plus the optional deviceModel, osVersion, appVersion, appBuild, and locale. Unknown fields are rejected rather than ignored. The response returns the device id, whether it was created, its status, and lastRegisteredAt — 201 for a new registration, 200 for a refresh.
The same 32 KiB body cap and 120-requests-per-minute-per-IP limit apply, counted separately from the push console’s budget. Registered devices are managed on Notifications.
This endpoint is deliberately narrower than
/api/ios/apns-devices. It serves
one first-party app, so it has no push-type catalog and no certificate
authentication.OpenAPI contract
The document is assembled at request time from the same Zod schemas the handlers validate against, so it cannot drift from the implementation. It describes the cookie and bearer security used by protected operations while leaving integration endpoints explicitly public. The document itself is served with
cache-control: public, max-age=300 and is the right thing to point a client generator at.
Browser and agent routes
The dashboard and the control agents use a handful of further routes. They are part of the application’s own plumbing rather than an integration surface, but they are worth knowing when reading logs:Public endpoints
Everything under/api/public/* is intentionally unauthenticated: iOS enrollment callbacks, short-lived build artifact and over-the-air manifest downloads, rate-limited crash report uploads, and the three signature-verified webhooks. Hosting and networking lists the full path set and explains how to expose exactly that namespace and nothing else.
MCP
/api/mcp is a stateless Streamable HTTP MCP endpoint. Point Claude Code, Cursor, or any other MCP client at it and the server’s built-in tools become callable directly.
The catalog spans agents, builds, codebases, worktrees, commands, workflows, runs, GitHub, GitLab, Jira, skills, notifications, signing, devices, disk space, usage, and debugging. Discovery tools include global_search, get_action_center, get_apps, get_app, get_installation_status, get_agent_cli_health, get_crash_reports, get_crash_report, get_dsyms, and get_dsym. Browse and export the catalog, run tools by hand, and inspect call history from Tools.
Scopes
The same endpoint serves three scopes, selected by query parameter:
Supplying both
preset and run, or either one twice, is rejected with 400 INVALID_MCP_SCOPE.
Run scope applies argument-level containment as well as tool-name grants. get_codebase_repository_preparations and save_codebase_repository_preparations may access only the logical repository attached to the run; a preset cannot let a run read or replace another repository’s rules.
Run creation resolves selected tools and stores their membership, advertised names, and schemas. A selected external server must be reachable and must still advertise each selected tool. A later preset edit does not alter an existing run’s snapshot. Legacy runs without mixed snapshots keep their built-in selections.
MCP clients can discover preset IDs with get_mcp_tool_presets and pass mcpPresetIds to create_agent_run, create_run_follow_up, or play_plan. This discovery tool accepts an optional kind of PLAN or SESSION.
Authentication
Unscoped and preset MCP calls require a signed-in user’s session or a Better Auth API key. Scripts should use anaide_ key in X-API-Key. The raw key is shown only once when you create it on API keys.
Correlation and auditing
Send anx-request-id header — up to 128 characters — and it is echoed back on the response and recorded as the call’s correlation ID. Without one, the server generates a UUID. Every call is written to the audit log on the Tools page with its caller, source, duration, and a SHA-256 hash of its arguments. Arguments themselves are never stored.
Callers are recorded by their Better Auth user or API-key identity. Run-scoped calls are recorded as agent:<agentId>@<address>.
Tool HTTP API
The Tools page drives two plain HTTP routes, which are also usable directly when you want a single tool call without speaking MCP:
Both Tools routes require a signed-in user session. They do not accept API keys or agent credentials.
POST /api/tools/call returns { "result", "requestId" } on success. Failures use INVALID_TOOL_CALL (400), CODEBASE_NOT_FOUND (404), TOOL_CALL_FAILED (502), or a 409 for an ambiguous codebase lookup.
External MCP servers
The Tools page manages and tests external Streamable HTTP or legacy SSE MCP servers. Their tools can be called from the Tools page, workflows, and scoped preset/run MCP connections. Saved custom header values stay server-side and are never returned to the browser.The bare
/api/mcp endpoint remains built-in only. External tools are
re-exported only through /api/mcp?preset=<id> and /api/mcp?run=<runId> when
selected for that scope.aide_ext_<identity-hash>_<tool-label> and are derived from the local server ID and raw upstream name. The same raw name on two servers therefore receives distinct aliases. Renaming a server or changing its catalog prefix does not rename a frozen run’s tools. Use the advertised alias for MCP tools/call; use the raw name with its server reference in preset documents.
External calls resolve credentials at call time. Credential rotation is supported, but a changed endpoint URL or transport is rejected for an existing run. Upstream content, structured results, and MCP error results pass through the scoped connection; failed external calls are recorded in the same tool-call audit as built-ins.
Related pages
GraphQL API
The generated schema reference, subscriptions, and Apollo Studio.
Tools
Browse the tool catalog, build presets, and read the audit log.
Hosting and networking
Which of these paths may be exposed publicly, and which must not be.
Local development
Regenerating the schema and resolver types.
External pipeline actions
externalPipelineActions(repositoryId:) returns the enabled flag, retry/cancel sources, and secret names. Use saveExternalPipelineActions, setExternalPipelineSecret, and deleteExternalPipelineSecret to configure a canonical repository. Existing secret values are never readable.
GitLabPipeline.canRetry/canCancel and GitLabJob.kind/targetUrl/canRetry/canCancel describe server-computed capabilities. Use runGitLabPipelineAction(projectId:, pipelineId:, action:, jobId:) for combined pipeline actions or one external status. Its optional execution reports component outcomes; externalPipelineExecutions returns the latest 20 sanitized records. Legacy pipeline mutations, MCP pipeline tools, and workflow actions use the same dispatch service. Agent credentials cannot manage this control-plane configuration.