Skip to main content

Application WebSocket API

Current routes, authentication boundary, message envelope, and recovery behavior for CodeGraph application WebSockets.

API Reference

Connect a client to WebSocket to stream chat answers, follow a background job, or display notifications without repeatedly polling the API. This reference helps integration developers choose among the three channels and implement authentication and message handling. Dashboard refresh events use a distinct authentication and message contract described in Dashboard WebSocket API.

Prerequisites

Sign in and obtain a valid access token. For project-bound access, prepare the project UUID and an explicit access grant for that user and project. The WebSocket checks this grant when the client sends X-Project-Id. Job subscriptions also need a job_id. Use your installation’s API address: wss for HTTPS and ws for a trusted local HTTP environment.

Authentication boundary

For chat and job status, send the token in the HTTP handshake header:

Authorization: Bearer <access-token>

Send the token through the authentication method for the route. A non-empty token query parameter causes the server to reject the HTTP handshake with status 403 before the WebSocket opens. The handler uses the rejection reason Query token transport is not allowed.

For project-bound access, also send the durable project identifier in the handshake:

X-Project-Id: <project-uuid>

The server verifies the current user state, token revocation, project access, job ownership where applicable, and connection/message quotas. A loopback client may omit credentials only when the explicit local-development unauthenticated-surface setting is enabled and both client and requested host are local.

Connect to chat and job status through a client that supports headers or an authenticated same-origin gateway. The notifications route supports browser WebSockets: after the connection opens, send the token as the first message within 5 seconds:

{"token": "<access-token>"}

After checking the token and access, the server sends connected. The client can then send ping and receive notifications. An authentication timeout closes the connection with code 1008 and reason Auth timeout.

Dashboard events are described in Dashboard WebSocket API.

Routes

Routes
Route Client messages Server purpose
/api/v1/ws/chat chat.query, ping Stream chat scenario selection, chunks, final response, completion, and errors
/api/v1/ws/jobs/{job_id} ping Send current and subsequent status for an owned background job
/api/v1/ws/notifications ping Push notifications for the authenticated user

The job route first checks subscription access. An unknown job or a job outside the caller’s scope produces Job subscription denied and close code 1008. After a subscription is authorized, the server reads the job state; if that read returns no job, it sends Job not found and closes with code 4004.

Message envelope

Every application message is JSON with this shape:

{
  "type": "chat.query",
  "payload": {},
  "timestamp": "2026-08-24T00:00:00Z",
  "request_id": "optional-correlation-id"
}

type is required. Omitted payload defaults to {} and timestamp to the current time. A chat.query needs payload.query. request_id is optional and should be preserved when correlating streamed chat messages.

Current message types

Current message types
Type Typical direction Meaning
chat.query client → server Start a chat request
chat.scenario server → client Report selected scenario
chat.chunk server → client Stream a partial answer
chat.response server → client Return the assembled answer
chat.done server → client Finish the request
chat.error server → client Report a chat-specific failure
job.started server → client Return initial or started job state
job.progress server → client Report job progress
job.completed server → client Report successful completion
job.failed server → client Report failed or cancelled completion
notification server → client Push a user notification
error server → client Report an envelope, policy, or processing error
ping client → server Ask for an application-level keep-alive response
pong server → client Respond to ping
cpg.update.complete server → client Report completed CPG update
connected server → client Confirm connection and return its identifiers
disconnected server → client Indicate a managed disconnect
authenticated server → client Confirm a supported authentication transition
auth_required server → client Request a supported authentication transition

Not every message type is produced by every route. Consumers must ignore recognized messages that are irrelevant to their current workflow and must not treat an unknown message as success.

Chat request

Send chat.query to the chat route:

{
  "type": "chat.query",
  "payload": {
    "query": "Show callers of the selected symbol",
    "session_id": "optional-session",
    "scenario_id": "optional-scenario",
    "language": "en"
  },
  "request_id": "req-123"
}

The values optional-session and optional-scenario stand for your session and scenario identifiers. Both fields are optional; omit them for a request without an explicit session or scenario.

The chat handler sends chat.scenario for scenario selection, chat.chunk for answer fragments, and chat.done when the response ends. Assemble the answer from the chunks and correlate them through request_id. A processing failure produces error with the same request identifier.

Job status

Connect to the job route with a job identifier owned by the authenticated user. The server sends job.started with the current status. For terminal states it follows with job.completed or job.failed. Retrieve the stored state through HTTP/REST and receive live notifications through WebSocket.

Notifications

The notifications route is receive-oriented. After authentication, send ping messages. The notification’s payload may contain title, message, level, and action_url. Validate action_url against the application’s navigation policy before opening it.

Connect to notifications

In this example, the service client sends X-Project-Id in the handshake to subscribe in a project context. This example uses Node.js and ws. In your client project directory, install the dependency with npm install ws, save the code as notifications.mjs, and run node notifications.mjs. Set CODEGRAPH_ACCESS_TOKEN, CODEGRAPH_PROJECT_ID, and CODEGRAPH_WS_URL through your approved configuration channel. The URL variable contains the full notifications route. Do not pass credentials as command-line arguments. The client sends the token first, waits for connected, then sends ping. The console prints pong. If the connection closes, it prints the close code and reason; 1008 project_access_denied means that the project access grant needs to be checked. Press Ctrl+C to stop the client.

import WebSocket from "ws";

for (const name of ["CODEGRAPH_ACCESS_TOKEN", "CODEGRAPH_PROJECT_ID", "CODEGRAPH_WS_URL"]) {
  if (!process.env[name]) throw new Error("Missing " + name);
}

const socket = new WebSocket(
  process.env.CODEGRAPH_WS_URL,
  {
    headers: {
      "X-Project-Id": process.env.CODEGRAPH_PROJECT_ID
    }
  }
);

socket.on("message", (raw) => {
  const message = JSON.parse(raw.toString());
  if (message.type === "notification") {
    console.log(message.payload);
  } else if (message.type === "connected") {
    socket.send(JSON.stringify({ type: "ping", payload: {} }));
  } else if (message.type === "pong") {
    console.log("pong");
  }
});

socket.on("open", () => {
  socket.send(JSON.stringify({ token: process.env.CODEGRAPH_ACCESS_TOKEN }));
});

socket.on("close", (code, reason) => {
  console.error("WebSocket closed:", code, reason.toString());
});

socket.on("error", () => {
  console.error("WebSocket connection failed; check the API address and server availability.");
});

Never log the token or full Authorization header.

Close codes and recovery

Rejections before the WebSocket opens appear as HTTP 403. The table describes server policy codes; clients receive a WebSocket close code only after a successful upgrade.

Close codes and recovery
Code Meaning Recovery
1008 Query-token, authorization, ownership, project-scope, or rate-limit policy failure Correct policy/input; do not retry in a tight loop
4001 Missing, invalid, expired, or revoked access token Obtain a new access token and reconnect
4004 Job state not found after subscription authorization Verify the job identifier through the REST API before reconnecting

Use bounded exponential backoff with jitter for transient disconnects. Refresh credentials before reconnecting after 4001. Do not automatically retry 1008 until the rejected condition has changed.

WebSocket routes are not part of the REST OpenAPI operation set.