Zeriq Teams API
Bring your AI teammates into your own systems: keep their knowledge in sync, ask them questions, run rooms, and track the action items that come out of them.
- Base URL:
https://api.zeriq.app/v1 - Reference: every endpoint, parameter and field is in the API reference. The OpenAPI 3.1 spec is at
https://api.zeriq.app/v1/openapi.json. - SDKs: official TypeScript and Python SDKs:
npm install zeriq-team(npm) andpip install zeriq-team(PyPI). They handle retries, idempotency keys, paging, live room streams and webhook verification. Any HTTP client works too.
1. Get an API key
Owners and admins create keys in Settings → Developers (Growth plan and up). Choose:
- Scopes, which say what the key may do (table below).
- Tool access: what AI teammates may do with tools when this key asks:
none(default)read_only(search and read only)allowed(an explicit list of tools, which may change things; Business plan)
- Optionally an IP allowlist and an expiry. A monthly credit cap can be set now; it will be enforced once per-key usage tracking ships.
The key (zqt_sk_live_…, or zqt_sk_test_… outside production) is shown once. Keep it on your server and never put it in a web page or mobile app: anyone who has it can act for your workspace within its scopes.
| Scope | Allows |
|---|---|
knowledge:read / knowledge:write | List, get and search documents / add, upsert and delete them |
personas:read | List AI teammates |
chat:read / chat:write | Read this key's conversations / ask AI teammates |
rooms:read / rooms:write | Read / run rooms this key created |
rooms:read:all | Read every room in the workspace (read only) |
tasks:read / tasks:write | List / create and update action items |
meetings:read | Meeting bots, transcripts and reports |
actions:execute | Needed with tools: "allowed" on ask |
webhooks:manage | Create and manage webhook endpoints |
2. First call
export ZERIQ_TEAM_API_KEY=zqt_sk_…
curl https://api.zeriq.app/v1/me -H "Authorization: Bearer $ZERIQ_TEAM_API_KEY"
It returns your workspace, the key's scopes and its tool access. The same call with the SDKs:
// npm install zeriq-team
import Zeriq from "zeriq-team";
const zq = new Zeriq(); // reads ZERIQ_TEAM_API_KEY
console.log(await zq.me());
# pip install zeriq-team
from zeriq_team import Zeriq
print(Zeriq().me()) # reads ZERIQ_TEAM_API_KEY
The SDKs use https://api.zeriq.app by default. Set ZERIQ_TEAM_BASE_URL to use another environment.
Ask an AI teammate next:
curl https://api.zeriq.app/v1/personas -H "Authorization: Bearer $ZERIQ_TEAM_API_KEY"
curl https://api.zeriq.app/v1/personas/prs_…/ask \
-H "Authorization: Bearer $ZERIQ_TEAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": "What changed in our refund policy?"}'
3. Conventions
-
IDs are prefixed:
doc_,room_,msg_,ai_(action item),bot_,prs_(persona),conv_,chk_(search chunk). -
Lists return
{"object": "list", "data": [...], "next_cursor": ...}. Passcursorfor the next page; it'snullon the last page. -
Errors look like
{"error": {"type", "code", "message", "param", "request_id"}}. Codes to handle:invalid_parameterinvalid_api_keyinsufficient_scope(paramis the missing scope)tool_not_permittedcredits_exhaustedplan_limitnot_found(also for other workspaces' objects)rate_limitednot_an_org_memberinvite_limit
-
Request IDs: every response has an
X-Request-Id. Quote it when you contact support. -
Idempotency: send an
Idempotency-Key(any unique string) on POSTs. A retry with the same key within 24 h gets the original response instead of doing the work twice. -
Rate limits are per key, per minute, by plan:
Plan Requests per minute Free 30 Growth 60 Business 300 - Calls that use AI credits count 6×.
knowledge/searchcounts ½.- Every response carries
RateLimit-Limit,RateLimit-RemainingandRateLimit-Reset. - A
429comes withRetry-After: wait that many seconds before retrying.
-
Credits: calls that use AI return
usage: {credits_charged, model, downgraded}and aZeriq-Credits-Remainingheader. The API never quietly switches to a cheaper model. When credits run out you getcredits_exhausted, unless you passallow_downgrade: true.
4. What you can build
Keep knowledge in sync
Upsert each document by your own external_id. A new version replaces the old one only once it's processed, so searches never see a gap. POST /knowledge/search returns the best passages with no AI model and no credits.
Ask an AI teammate
POST /personas/{id}/ask {input, conversation_id?, use_knowledge?, tools?, model?, allow_downgrade?} returns:
- the answer
- citations
tools_usedconversation_id, to continue the threadusage
Run rooms
POST /rooms with AI teammates (personas) and, optionally:
- people from your workspace (
members: [{email} | {member_id}]). Only current members can be added; anyone else gets400 not_an_org_member. - a
host, who can also end the room in the web app. notify: "email" | "none". Invites are limited to 50 people per key per day.
Your key posts as itself and shows as "via " in the web app; it can never post as a person. Teammates reply in the background. The response to your message has a run_id: stream that run's events (section 6, Live room events), or poll GET /rooms/{id}/messages?after=<your message id>. POST /rooms/{id}/end generates the summary, action plan and action items.
A key sees only the rooms it created, unless it has rooms:read:all.
Track action items
GET /action-items?room_id&status&assignee&since lists them across every room you can read. PATCH /action-items/{id} {status?, external_ref?} links one to where it's tracked, e.g. a Linear issue or a PR.
Meetings
Read-only for now: bots, transcripts and reports under /meetings/bots.
5. Webhooks
Instead of polling, let Zeriq tell you when something happens. Add an https endpoint in Settings → Developers, or with POST /webhooks/endpoints (scope webhooks:manage). You can choose which events it gets; by default it gets all of them. The signing secret (whsec_…) is shown once.
Each delivery is a POST with a JSON body:
{"id": "evt_…", "type": "action_item.created", "created": 1767225600, "org_id": "…", "data": {"action_item": {…}}}
data uses the same shapes as the API: a room, message, action_item, document or bot.
Check the signature before trusting a delivery. The SDKs do it for you with verifyWebhook(rawBody, header, secret) (TypeScript) and zeriq_team.webhooks.verify(raw_body, header, secret) (Python), or you can write it yourself. The Zeriq-Signature header is t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of <t>.<raw body> keyed with your secret:
- Compare the HMAC in constant time.
- Reject a
tolder than 5 minutes. - Use the raw body exactly as received; parsed and re-serialized JSON won't match.
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const signatures = header.split(",").filter((p) => p.startsWith("v1=")).map((p) => p.slice(3));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return signatures.some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}
import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = [p.split("=", 1) for p in header.split(",")]
t = next(v for k, v in parts if k == "t")
if abs(time.time() - int(t)) > 300:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return any(hmac.compare_digest(expected, v) for k, v in parts if k == "v1")
Retries:
- Answer with any
2xxwithin 10 seconds. Anything else, or no answer, is retried for about a day: after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, then 8 hours twice. - Deliveries are at least once, so use the event
idto ignore repeats. - If deliveries keep failing for 3 days, the endpoint is turned off and your workspace's admins get an email. Fix it, then turn it back on.
Other tools:
- Send test delivers a
webhook.testevent right away and shows the response. - The deliveries log (
GET /webhooks/deliveries) shows each attempt's status code, timing and error, and can send again. - Rotate secret issues a new one. For 24 hours, deliveries carry a second
v1=signed with the old secret, so you can switch without missing any.
| Event | When |
|---|---|
room.created, room.ended | A room starts or ends |
room.message.created | A message is posted by a person, an AI teammate or an API key |
room.summary.ready, room.report.ready | A summary or report is generated |
action_item.created, action_item.updated | An action item is added, marked done or open, or linked |
document.ready, document.failed | A document finishes processing |
meeting.bot.status_changed, meeting.report.ready | A meeting bot's status changes; its report is ready |
credits.low | Credits fall below 15% of the monthly allowance |
6. Live room events
GET /rooms/{id}/events streams a room's events as server-sent events (scope rooms:read):
| Event | When |
|---|---|
persona.thinking | AI teammates started on a reply (personas) |
message.created | A message from a person, an AI teammate or an API key (message) |
run.completed | A reply run finished (replies: how many messages it posted) |
run.failed | A reply run stopped with an error |
Each event's data has type, room_id and run_id (null for messages that aren't part of a run).
RUN=$(curl -s https://api.zeriq.app/v1/rooms/$ROOM/messages -H "Authorization: Bearer $ZERIQ_TEAM_API_KEY" \
-H "Content-Type: application/json" -d '{"content":"Should we ship Friday?"}' | jq -r .run_id)
curl -N "https://api.zeriq.app/v1/rooms/$ROOM/events?run_id=$RUN" -H "Authorization: Bearer $ZERIQ_TEAM_API_KEY"
id: evt_…
event: persona.thinking
data: {"type":"persona.thinking","room_id":"room_…","run_id":"run_…","personas":[{"id":"prs_…","name":"Priya"}]}
id: evt_…
event: message.created
data: {"type":"message.created","room_id":"room_…","run_id":"run_…","message":{…}}
id: evt_…
event: run.completed
data: {"type":"run.completed","room_id":"room_…","run_id":"run_…","replies":1}
How the stream behaves:
- With
run_id: it replays that run from its start, so connecting a moment late misses nothing, and it ends when the run does. - Without
run_id: it streams everything live. - Resuming: send the last
idyou received as theLast-Event-IDheader to resume (browsers'EventSourcedoes this for you). - Keep-alive and timeout: a
: keep-alivecomment comes every 15 seconds, and a stream closes after 10 minutes, so reconnect withLast-Event-ID.
7. AI tools (MCP)
Claude, VS Code, Cursor and other AI tools can use your workspace through its MCP server at https://api.zeriq.app/mcp (Streamable HTTP).
Connecting:
- Add the URL in the tool, e.g.
claude mcp add --transport http zeriq https://api.zeriq.app/mcp. - The tool opens a Zeriq page where you sign in, pick what it may do, and connect your current workspace. Actions are unchecked unless you tick them.
- For tools that can't sign in (CI, scripts), create a personal access token (
zqt_pat_…) in Settings → Developers and send it asAuthorization: Bearer ….
What it can do: the tool acts as you, so it only sees rooms you're in, limited to what you allowed.
- Read tools:
search_knowledge,list_documents,get_document,list_personas,list_rooms,get_room,get_room_transcript,get_room_run,list_action_items,list_meetings,get_meeting_report,get_credits. - Write tools:
add_to_knowledge,ask_persona,start_room,post_room_message,end_room,update_action_item. Ones that use AI spend credits as in the web app.- Room runs:
start_roomandpost_room_messagecan run as tasks: the tool returns a task id at once, and the client follows it withtasks/get/tasks/result, even after a restart. Older clients pollget_room_run. - Confirmation:
end_room, andask_personawithtools: "allowed"(letting a teammate take actions in your connected tools), ask you to confirm in your AI tool first. Clients that can't show that confirmation can't do these at all. - Room runs and tools: room runs started from MCP use read-only tools at most.
- Room runs:
- Resources:
team://rooms/{id}/summary,team://rooms/{id}/action-plan,team://documents/{id},team://action-items/{id}. - Prompts:
meeting_prep,implement_action_item,standup_digest.
Plans:
- MCP works on every plan except guest workspaces, within the plan's rate limits.
- Personal access tokens: 1 per person on Free, 5 on Growth, 20 on Business.
- Letting teammates take actions in connected tools needs the Business plan.
Admin controls (Settings → Developers → MCP): owners and admins can:
- turn MCP off for the workspace
- limit which knowledge sources it returns
- allow meeting transcripts. This is off by default, because transcripts contain what guests said and AI tools send what they read to their model provider.
- choose which actions AI tools may let teammates take. The list is empty by default.
Every call is audited.
Coming next
- Usage: per-key usage reporting.