New TypeScript integrations should use
@swarmd/channel-client. It wraps the Conversation REST API, OAuth token refresh, polling, reply extraction, and typed lifecycle events. The JSON-RPC path documented here still works and remains supported; this guide is kept for existing integrations and protocol-level reference.Frontend Integration (JSON-RPC — legacy)
This guide covers how to integrate your frontend application with Swarmd agents using the JSON-RPCa2a/0.3.0 protocol. It applies to both channel-based access (for apps, bots, and services) and user-based access (for logged-in humans). Both access types use the same JSON-RPC protocol and follow the same request/response patterns — the only difference is the endpoint and how you authenticate.
Access Types at a Glance
Authentication
Channel Authentication
Channels authenticate using the OAuth2 client credentials flow. You received aclientId and clientSecret when the channel was created (see Your First Agent).
The
client_id is always the channel’s clientId field — formatted as channel-{channelId}. The token is short-lived (typically 5 minutes). Your app should refresh it before expiry by repeating the same request.User Authentication
Users authenticate via the Swarmd login endpoint:Listing Available Agents
Before invoking an agent, your frontend may need to display a list of available agents.Channel: List Subscribed Agents
This endpoint requires a user Bearer token (from login), not a channel token. Channel management operations (creating, subscribing, listing) are admin actions performed by logged-in users.
User: List Subscriptions
Sending a Request
Every interaction starts with amessage/send call. The request body is identical for both access types — only the endpoint differs.
- Channel
- User
The Two Flows
There are two distinct scenarios depending on whether you call the agent directly or through a chain. These apply regardless of whether you use channel or user access.Flow 1: Direct Agent Call
You call an agent directly and that agent’s response triggers HITL review.Flow 2: Multi-Agent Chain
You call Agent A, which delegates to Agent B. Agent B’s response triggers HITL review. Agent A waits for Agent B to resolve before responding to you.Every Response Your App Can Receive
1. completed — No Review Needed
The agent responded immediately with no HITL involved. Render the response and you’re done.
result.status.message. No polling needed.
How to detect: result.status.state === "completed".
2. working — Relay-Managed Task, You Must Poll
The relay has taken ownership of this task and returned immediately so your request doesn’t hang. The metadata.relay_reason field tells you why.
How to detect: result.status.state === "working" and result.metadata.relay_reason is present.
Action (all cases):
- Save
result.id— this is the task ID you’ll poll with - Start polling
tasks/get(see How to Poll below) - Show context-appropriate UI based on
relay_reason(see below)
TIMEOUT — Agent is Slow
The agent didn’t respond within the relay’s early-return timeout. The relay is still waiting for the agent in the background.
HITL_HELD — Policy Escalation
A detection policy (regex, Presidio, Comprehend) matched the message content and escalated it for human review. The metadata includes the triggering policy details so your UI can display context.
HITL_HELD_AGENT_INPUT_REQUIRED — Agent Requested Human Input
The downstream agent explicitly returned INPUT_REQUIRED, requesting human confirmation before proceeding. No policy was involved — the agent made this decision itself.
3. canceled — HITL Rejected
A human reviewer rejected the HITL request. If a policy triggered the original hold, the metadata includes the policy details.
The
HITL_REJECTED reason can appear both in the initial message/send response (if the rejection happened before the relay returned) and in tasks/get poll responses. The policy_name, policy_version, and policy_level fields are nullable — they are null when the original hold was agent-initiated rather than policy-triggered.relay_reason Reference
policy_level Values
How to Poll
Send atasks/get request to the same endpoint you used for the original message/send:
- Channel
- User
Poll every 5 seconds until you receive a terminal state.
Poll Responses
Still Pending
The review hasn’t been resolved yet. Keep polling.Approved — Direct Agent
An admin approved the request. The agent processed it and returned a result.result.artifacts[0].parts or result.status.message as the agent’s response.
Approved — Multi-Agent Chain
An admin approved a downstream agent’s HITL request. The parent agent received the downstream result, combined it with its own data, and returned a single complete answer.Rejected — Direct Agent
An admin rejected the request. The task is canceled and the agent did not process it.Rejected — Multi-Agent Chain
An admin rejected a downstream agent’s HITL request. The parent agent continues without the downstream agent’s data and responds with whatever information it had on its own.No data is leaked when a downstream agent is rejected. The rejected agent’s response is never forwarded — the parent agent receives
null for the delegation and has no access to the blocked agent’s data. The parent can only respond with information it already had independently (in this example, the time). The HITL rejection acts as a hard gate: if it’s rejected, that agent’s data does not flow anywhere in the chain.Terminal States Reference
Stop polling when you see any of these states:Decision Flowchart
Polling Best Practices
The polling endpoint is the same as the endpoint you used for
message/send:
Key Fields Reference
Conversation Continuity
After a request resolves (whether HITL-blocked or not), usecontextId from the response for follow-up messages. The agent retains the full conversation history.
- Channel
- User
Channel vs User: Differences for HITL
While the request/response format is identical, there are differences in how HITL policies are applied:Both channel and user access support the full HITL workflow. The only difference is which policies are evaluated. If you’ve bound a HITL detection policy at the tenant level, it will apply to channel requests too. User-scoped policies (bound to specific users) only apply to user access.
Summary
Next Steps
Human-in-the-Loop Setup
Configure HITL policies and manage approvals.
Policy Configuration
Set up detection policies that trigger HITL escalation.
