Skip to main content
GET /v1/connect is a WebSocket upgrade endpoint used by deployed workers to receive jobs dispatched from the AgentMark platform. Unlike the rest of the gateway API, this endpoint uses a persistent WebSocket connection rather than request/response HTTP.
Most developers should not call this endpoint directly. Use the @agentmark-ai/connect package, which handles the handshake, heartbeats, reconnection with exponential backoff, and the job-message protocol.The URL and handshake-phase error shapes documented here are a stable contract; the post-upgrade message protocol is considered SDK-internal and may change between SDK versions without warning.

Base URL

wss://api.agentmark.co/v1/connect
http:// maps to ws://; https:// maps to wss://. The same URL is returned by GET /internal/cli/connect-config for the agentmark dev CLI.

Authentication

WebSocket upgrades use the same API key authentication as other /v1/* endpoints. Unlike browser WebSockets (which can’t set custom headers), SDK clients running in Node.js, Bun, or similar runtimes set the Authorization header directly during the handshake.
HeaderValue
AuthorizationBearer sk_agentmark_...
Upgradewebsocket
X-Agentmark-SDK-Version (optional)SDK version string, used for connection tracking
X-Agentmark-Adapter (optional)Adapter name (e.g. vercel-ai-v5)
X-Agentmark-Language (optional)typescript or python
The API key’s X-Agentmark-App-Id is encoded in the key itself — no separate header is required for this endpoint.

Handshake lifecycle

  1. Client sends an HTTP GET /v1/connect request with Upgrade: websocket and the Authorization header.
  2. Gateway verifies the API key, looks up the tenant and app, and forwards the upgrade request to the per-app Durable Object.
  3. Gateway responds 101 Switching Protocols on success, or an HTTP error (see below) if the handshake is rejected.
  4. Client and gateway exchange heartbeat messages to keep the connection alive. The SDK handles this automatically.
  5. Gateway sends job messages when the dashboard or an API caller dispatches work to this app.
  6. Client responds with job results (streaming or non-streaming) framed as WebSocket messages.
Exact message shapes are defined in the @agentmark-ai/connect source. The protocol is not part of the OpenAPI spec because OpenAPI 3 has no first-class support for WebSocket messages.

Handshake-phase errors

If the handshake fails, the gateway returns an HTTP error response before upgrading to WebSocket. These responses use the same canonical error envelope as the rest of the /v1/* API:
{
  "error": {
    "code": "string_snake_case",
    "message": "Human-readable description"
  }
}
Statuserror.codeWhen it happens
426not_implementedRequest arrived without an Upgrade: websocket header. This endpoint serves only WebSocket upgrades.
400missing_required_fieldAuthentication succeeded but the API key is not bound to an app ID. Check your API key configuration.
401unauthorizedMissing, malformed, or invalid Authorization header.
403forbiddenAPI key is valid but has been revoked or lacks the required permission.
429span_limit_exceeded | storage_cap_exceededThe account has exceeded its monthly quota. See Rate Limiting.
After upgrade, errors are delivered as WebSocket messages rather than HTTP status codes — see the SDK source for the message format.

Connection behavior

The connection is designed to stay open indefinitely. Expected behaviors:
  • Heartbeat — the SDK sends periodic heartbeat messages. Missed heartbeats beyond the threshold (90 seconds by default) cause the gateway to close the socket with code 1000.
  • Duplicate connect — if an app opens a second connection, the prior connection is closed with code 1000 and reason "Replaced by new connection". There is one active socket per app.
  • Reconnect — the SDK implements exponential-backoff reconnection on unexpected close. Max delay is 60 seconds by default.
  • Hibernation — the gateway Durable Object uses Cloudflare’s WebSocket Hibernation API; connections can survive short periods of worker eviction without the client noticing.

Example

Using the SDK (strongly recommended):
import { createConnectServer } from "@agentmark-ai/connect";

const server = createConnectServer({
  apiKey: "sk_agentmark_...",
  handler: async (job) => {
    // ... your job handler here
    return { type: "result", result: JSON.stringify(...) };
  },
});

await server.start();
Raw (for reference — not recommended for production):
const ws = new WebSocket("wss://api.agentmark.co/v1/connect", {
  headers: {
    Authorization: "Bearer sk_agentmark_...",
    "X-Agentmark-SDK-Version": "my-client/0.1.0",
  },
});

ws.on("open", () => console.log("connected"));
ws.on("message", (raw) => {
  const msg = JSON.parse(raw.toString());
  // ... handle job message
});

Why this endpoint is not in the OpenAPI spec

OpenAPI 3 describes request/response HTTP; it does not describe WebSocket message exchange. Documenting /v1/connect here as prose rather than in the OpenAPI spec is deliberate:
  • The handshake-phase HTTP errors (426/400/401/403/429) use the same canonical envelope as every other /v1/* route — so the existing SDK error handling works here too.
  • The post-upgrade message protocol is considered an implementation detail of the SDK. The SDK is the contract; the wire protocol may evolve without constituting a breaking API change.
If this becomes a problem (e.g. a third-party SDK in a new language needs to implement the protocol from scratch), the path forward is to publish an AsyncAPI spec alongside the OpenAPI spec. That’s a deliberate future step, not a limitation of today’s setup.