Jian/ Docs

HTTP API and client integrations

Owner API, channel-compatible chat, asynchronous runs, and idempotent requests.

Jian exposes two different integration surfaces: the owner API for administering and driving a gateway, and an OpenAI-compatible chat surface belonging to an API channel. Use the credential appropriate to the surface.

The authoritative schema for a running gateway is GET /openapi.json. The repository generates it from Zod contracts and generates a TypeScript client from the same contract. This guide is a working orientation, not a replacement for your installed version's schema.

Addresses and authentication

SurfaceBase/pathCredential
Owner API/v1/...Authorization: Bearer <host token>
OpenAI-compatible API channel/v1/channels/{channelId}/openaiChannel token as a bearer
Native channel ingress/v1/ingress/{channelId}x-jian-channel-token
Public probes/health, /openapi.jsonNone

Use the public web-panel origin for a server deployment. The web host forwards these requests to its gateway. Never put owner tokens in a frontend bundle or a public URL.

Inspect an existing installation

Set JIAN_HOST_TOKEN securely in the shell before using these examples. It is an example client variable, not an additional gateway setting. All example domains and IDs below are fictional.

JIAN_BASE_URL='https://jian.example.com'
curl --fail-with-body "$JIAN_BASE_URL/health"
curl --fail-with-body \
  -H "Authorization: Bearer $JIAN_HOST_TOKEN" \
  "$JIAN_BASE_URL/v1/profiles"

Take the intended profile ID from the returned data. Creating a conversation and submitting a message are writes and can consume model usage.

Open a conversation and submit a turn

A panel-style conversation is created through gateway-sessions. Its body can select projectId or remoteMachineId; an empty object uses the default target.

JIAN_PROFILE_ID='11111111-1111-4111-8111-111111111111'
curl --fail-with-body \
  -H "Authorization: Bearer $JIAN_HOST_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{}' \
  "$JIAN_BASE_URL/v1/profiles/$JIAN_PROFILE_ID/gateway-sessions"

Use the returned session ID in the next path. Prepare the request body as message.json:

{
  "text": "Summarize the three next steps for Harbor Studio. Do not change any external data.",
  "requestKey": "harbor-planning-001"
}
JIAN_SESSION_ID='22222222-2222-4222-8222-222222222222'
curl --fail-with-body \
  -H "Authorization: Bearer $JIAN_HOST_TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary @message.json \
  "$JIAN_BASE_URL/v1/profiles/$JIAN_PROFILE_ID/sessions/$JIAN_SESSION_ID/messages"

Submission returns 202 with run information. It means work was accepted, not that the final answer or an external effect has completed. Reuse the same request key when retrying the same submission after an uncertain network result. Give genuinely new messages new keys.

The message contract allows text up to 8,000 characters and a request key up to 120. Attachments use previously stored media IDs; a message needs text or an attachment.

Follow execution

Method and path suffix under /v1/profiles/{profileId}Purpose
GET /runs/{runId}Current run state/result
POST /runs/{runId}/cancelRequest cancellation
GET /runs/{runId}/checkpointsInspect persisted execution checkpoints
POST /runs/{runId}/approvalDecide an approval using the contract's decision body
POST /runs/{runId}/answerAnswer a structured question
GET /sessions/{sessionId}/messagesConversation messages
GET /sessions/{sessionId}/timelineConversation activity
GET /sessions/{sessionId}/contextContext usage and compaction information
PUT /sessions/{sessionId}/protectionSet ask, auto, or full for an owner-controlled session
PUT /sessions/{sessionId}/objectiveManage a persistent objective

Use /openapi.json for the exact approval, answer, media, and objective schemas. A run can wait for human input; clients should not classify every non-completed state as failure or start duplicate work to escape a wait.

OpenAI-compatible chat

Create an API channel on a server agent. Configure a client with:

Base URL: https://jian.example.com/v1/channels/33333333-3333-4333-8333-333333333333/openai
API key:  the channel token
Model:    default, or a model ID returned by GET /models

GET /models lists default and available model IDs. POST /chat/completions accepts a body such as:

{
  "model": "default",
  "user": "harbor-client",
  "metadata": { "chat_id": "harbor-planning" },
  "messages": [
    { "role": "user", "content": "What should I prepare for the project review?" }
  ],
  "stream": true
}

The example can be sent with curl using the channel token stored privately in JIAN_CHANNEL_TOKEN:

curl --no-buffer --fail-with-body \
  -H "Authorization: Bearer $JIAN_CHANNEL_TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary @chat.json \
  "$JIAN_BASE_URL/v1/channels/$JIAN_CHANNEL_ID/openai/chat/completions"

Save the JSON above as chat.json and set JIAN_CHANNEL_ID to the API channel's ID before running it. Streaming returns text/event-stream chunks, ending with data: [DONE] on normal completion. Errors after the stream starts arrive in the stream rather than changing the already-sent HTTP status.

Compatibility boundaries

This endpoint drives a persistent Jian agent; it is not a transparent proxy to the complete OpenAI API.

  • Only the last user message's text becomes the new request. Image parts are accepted but ignored by this compatibility surface.
  • metadata.chat_id keeps conversation identity stable. Without it, Jian derives an identity from the channel and opening system/user messages.
  • user identifies the channel contact; absent it, the adapter uses its default actor.
  • Resent history helps identify the conversation but is not installed wholesale as a replacement for gateway history. Client system instructions do not replace the agent's configured identity.
  • Fields such as temperature, tools, or n can be tolerated without being implemented. The agent's runtime and settings control execution.
  • reasoning_effort and the Jian protection extension are supported by the contract. API channels refuse full protection.
  • The body limit is 4 MB with up to 2,000 messages; the new user text remains capped at 8,000 characters.

Use normal media APIs/channels for attachments requiring full Jian processing. Do not infer support for Responses, embeddings, or another API merely from Chat Completions compatibility.

Contact gates and client disconnects

A pending API contact returns 403 with an approval explanation. A paused conversation can return 409; missing model setup can return 503. Resolve the actual state in Jian instead of rotating unrelated provider keys.

If a client disconnects, the gateway run continues. Its result remains in the conversation. After an uncertain request, inspect or retry the same logical turn rather than inventing a new conversation ID.

Native ingress

Native ingress is useful when you control the channel integration. A minimal body is:

{
  "actorId": "harbor-client",
  "chatId": "harbor-planning",
  "text": "Prepare a concise project review outline.",
  "requestKey": "harbor-review-001"
}

POST /v1/ingress/{channelId} authenticates with x-jian-channel-token. A 202 response can still contain accepted: false and contact: pending. Check the body and run ID: HTTP receipt alone is not proof of model execution or reply delivery.

Implementation reference

Session routes, OpenAI-compatible routes, and compatibility contract.

On this page