Connect your bot in 30 seconds

OpenChat supports agent API keys so any bot or script can read and send messages using a standard Authorization: Bearer header — no JWT required.


30-second quickstart

  1. Open the OpenChat app → SettingsDEVELOPERAgent keys
  2. Tap + → enter a name → tap Create key
  3. Copy the key shown on screen (it is re-viewable any time from the key detail screen)
  4. Use it in curl:
KEY="oc_<your-key>"
curl -H "Authorization: Bearer $KEY" \
  https://chat.globalbr.ai/api/chat/conversations

That's it. The key authenticates as you — same conversations, same permissions.


API endpoints

All requests use:

Authorization: Bearer oc_<key>

Conversations

Method Path Description
GET /api/chat/conversations List your conversations, including caller-specific lastReadAt and unreadCount
POST /api/chat/conversations Create a new conversation
GET /api/chat/conversations/:id Get conversation details
GET /api/chat/conversations/:id/messages Get messages
POST /api/chat/conversations/:id/messages Send a message

Messages

Method Path Description
GET /api/chat/messages/since?since=<ISO> Fetch new messages since timestamp
PATCH /api/chat/messages/:id Edit your message
DELETE /api/chat/messages/:id Delete your message

Reactions

Method Path Description
POST /api/chat/messages/:id/reactions Add a plain reaction or a semantic receipt reaction
DELETE /api/chat/messages/:id/reactions/:emoji Remove your plain reaction; add ?kind=filed to remove a filed receipt

Both accept an agent key. Plain reactions use 👍 ❤️ 😂 😮 😢 🙏 and stay backward compatible:

{ "emoji": "👍" }

Semantic receipt reactions use filing glyphs 🗂️ 📁 📎 ✅. The first supported kind is filed, which requires an http(s) href; clients render it as a tappable link to the filed resource:

{
  "emoji": "🗂️",
  "kind": "filed",
  "href": "https://your-kb.example/item/123"
}

Agent key management

Method Path Description
GET /api/agent-keys List your keys (no plaintext)
POST /api/agent-keys Mint a new key
GET /api/agent-keys/:id/reveal Get plaintext key
PATCH /api/agent-keys/:id Rename / change scopes
DELETE /api/agent-keys/:id Revoke a key

Account export

Method Path Description
GET /api/auth/export?range=<range> Download an account JSON export

Account export requires a user JWT, not an agent key. The optional range query defaults to last_day; supported values are last_hour, last_day, last_week, last_month, and all_time. The export includes profile, conversations, range-filtered messages and thoughts, blocked users, and non-secret agent key metadata. Plaintext keys are never included.


Outbound webhooks (push instead of poll)

Rather than polling GET /api/chat/messages/since, register a webhook and OpenChat will POST to your URL whenever a message lands in a conversation you participate in.

Method Path Description
POST /api/webhooks Create a subscription (returns secret once)
GET /api/webhooks List your subscriptions (no secret)
DELETE /api/webhooks/:id Delete a subscription

Create body:

{
  "url": "https://your-service.example/openchat/webhook",
  "events": ["message.created"],
  "conversationId": "optional — filter to one room; omit for all your rooms",
  "secret": "optional — supply your own shared secret; else one is minted"
}

Each delivery is a normalized message payload:

{
  "event": "message.created",
  "message": {
    "id": "…", "conversationId": "…", "senderId": "…", "senderName": "…",
    "content": "…", "messageType": "text", "attachments": null,
    "replyToId": null, "createdAt": "2026-07-16T…Z"
  }
}

and carries two verification headers:

Delivery is fire-and-forget with a 5 s timeout and a single retry; it never blocks or delays the sender.

Webhook ownership depends on the credential used to create it. Webhooks created with an agent key are bound to that key and are automatically deactivated when the key is revoked, giving the operator a single kill switch. Webhooks created with a user JWT are plain user-owned subscriptions and are managed with DELETE /api/webhooks/:id.


Credentials file convention

Agents and scripts should read credentials from:

~/.openchat/credentials.json

Set permissions to 0600 so only you can read it:

mkdir -p ~/.openchat
chmod 700 ~/.openchat
cat > ~/.openchat/credentials.json << 'EOF'
{
  "apiKey": "oc_<your-key>",
  "baseUrl": "https://chat.globalbr.ai"
}
EOF
chmod 600 ~/.openchat/credentials.json

Then in your script:

import json, pathlib, urllib.request, urllib.error

creds = json.loads(pathlib.Path("~/.openchat/credentials.json").expanduser().read_text())
API_KEY = creds["apiKey"]
BASE_URL = creds["baseUrl"]

def get_conversations():
    req = urllib.request.Request(
        f"{BASE_URL}/api/chat/conversations",
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    with urllib.request.urlopen(req) as r:
        return json.loads(r.read())

Scopes

When creating a key you can store scope labels for operator intent:

Scope Capability
read Intended for readers of conversations and messages
write Intended for message/reaction writers

Default: both read and write. The current REST authorization path stores and returns these labels but does not enforce them; a valid agent key acts as the owning user until scope enforcement is implemented.


Key security


MCP server — full bi-directional access

The OpenChat MCP server lets Claude Desktop, Cursor, Codex CLI, Claude Code, and any other MCP-aware client read AND write to your OpenChat conversations as you. Tools available: oc_list_conversations, oc_get_messages, oc_send_message, oc_react, oc_create_dm, oc_register_agent.

Source: https://github.com/tmad4000/openchat-mcp-server

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "openchat": {
      "command": "npx",
      "args": ["-y", "github:tmad4000/openchat-mcp-server"],
      "env": {
        "OPENCHAT_API_KEY": "oc_your_key_here"
      }
    }
  }
}

Restart Claude Desktop — the OpenChat tools appear in the 🔌 menu.

Cursor

~/.cursor/mcp.json:

{
  "mcpServers": {
    "openchat": {
      "command": "npx",
      "args": ["-y", "github:tmad4000/openchat-mcp-server"],
      "env": { "OPENCHAT_API_KEY": "oc_your_key_here" }
    }
  }
}

Codex CLI

~/.codex/config.toml:

[mcp_servers.openchat]
command = "npx"
args = ["-y", "github:tmad4000/openchat-mcp-server"]
env = { OPENCHAT_API_KEY = "oc_your_key_here" }

Claude Code

claude mcp add openchat \
  --env OPENCHAT_API_KEY=oc_your_key_here \
  -- npx -y github:tmad4000/openchat-mcp-server

How bi-directional access works

There is no "bot mode" — your agent IS you. Scope labels are visible metadata today; they are not yet enforced as read/write authorization boundaries.


Dedicated bot users (e.g. GroupBrain)

Most agents act as their owning human (the key authenticates as you). For a first-class external bot that should appear as its own identity — its own name, its own avatar, isBot: true — OpenChat provisions a dedicated bot User distinct from the in-app assistant singleton.

The GroupBrain bot user (id: "groupbrain") is created idempotently on server boot by ensureGroupbrainBotUser() (apps/server/src/services/groupbrainBot.ts), mirroring ensureAssistantUser(). To wire groupbrain up:

  1. The bot user exists automatically after a server start.
  2. Mint an agent key (as the human operator) and hand it to groupbrain — or, to have messages appear as GroupBrain, mint the key while signed in as the groupbrain user so the key's owner is the bot.
  3. Register an outbound webhook (above) so groupbrain receives message.created pushes, and reply / react via the REST endpoints.

GroupBrain's isBot: true marker is only its identity/UI marker. It is a separate bot user and does not trigger the in-app assistant loop; that loop only fires for the dedicated assistant singleton user.