Chat API Reference
Hasura Lite GraphQL API
Base endpoint: https://chat-testing.thephenom.app/api/graphql
Authentication: Authorization: Bearer <Cognito ID Token> header on all requests. The token must contain x-hasura-* claims.
Queries
chat_rooms – List Rooms
query ListRooms {
chat_rooms(where: { is_active: { _eq: true } }) {
id
name
description
created_at
is_active
}
}
Response:
{
"data": {
"chat_rooms": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Phenom Internal",
"description": "Internal team chat",
"created_at": "2026-03-15T00:00:00+00:00",
"is_active": true
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Phenom Partners",
"description": "Partner and collaborator chat",
"created_at": "2026-03-15T00:00:00+00:00",
"is_active": true
},
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"name": "Phenom Community",
"description": "Community chat for mobile app users",
"created_at": "2026-03-15T00:00:00+00:00",
"is_active": true
}
]
}
}
chat_messages – Query Messages
Fetch messages with pagination and filtering. Messages are ordered newest-first by default.
query GetMessages(
$roomId: uuid!
$limit: Int!
$before: timestamptz
) {
chat_messages(
where: {
room_id: { _eq: $roomId }
is_deleted: { _eq: false }
created_at: { _lt: $before }
}
order_by: { created_at: desc }
limit: $limit
) {
id
room_id
user_id
content
message_type
phenom_id
is_deleted
created_at
updated_at
user {
id
username
display_name
avatar_url
}
link_preview {
url
title
description
thumbnail_url
media_type
}
}
}
Variables:
{
"roomId": "550e8400-e29b-41d4-a716-446655440003",
"limit": 50,
"before": "2026-03-22T12:00:00Z"
}
Filter messages by a specific user:
query MessagesByUser($roomId: uuid!, $userId: String!, $limit: Int!) {
chat_messages(
where: {
room_id: { _eq: $roomId }
user_id: { _eq: $userId }
is_deleted: { _eq: false }
}
order_by: { created_at: desc }
limit: $limit
) {
id
content
created_at
user { username }
}
}
chat_members – Query Members
query GetMembers($roomId: uuid!) {
chat_members(
where: { room_id: { _eq: $roomId } }
order_by: { joined_at: asc }
) {
user_id
role
is_muted
muted_until
joined_at
user {
username
display_name
avatar_url
}
}
}
Mutations
insert_chat_messages_one – Send Message
mutation SendMessage($roomId: uuid!, $content: String!) {
insert_chat_messages_one(
object: {
room_id: $roomId
content: $content
}
) {
id
content
message_type
created_at
user {
id
username
}
}
}
Variables:
{
"roomId": "550e8400-e29b-41d4-a716-446655440003",
"content": "Hello from the Phenom community!"
}
Send a Phenom link message (triggers link preview resolution):
mutation SendPhenomLink($roomId: uuid!, $content: String!, $phenomId: String!) {
insert_chat_messages_one(
object: {
room_id: $roomId
content: $content
message_type: "phenom_link"
phenom_id: $phenomId
}
) {
id
content
message_type
phenom_id
created_at
}
}
update_chat_messages_by_pk – Soft Delete Message
Requires support or admin role.
mutation DeleteMessage($messageId: uuid!, $deletedBy: String!) {
update_chat_messages_by_pk(
pk_columns: { id: $messageId }
_set: {
is_deleted: true
deleted_by: $deletedBy
}
) {
id
is_deleted
}
}
Variables:
{
"messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"deletedBy": "admin-user-uuid"
}
insert_chat_bans_one – Ban User
Requires admin role.
mutation BanUser(
$roomId: uuid!
$userId: String!
$bannedBy: String!
$reason: String
$expiresAt: timestamptz
) {
insert_chat_bans_one(
object: {
room_id: $roomId
user_id: $userId
banned_by: $bannedBy
reason: $reason
expires_at: $expiresAt
}
) {
id
user_id
reason
banned_at
expires_at
}
}
Variables (temporary ban – 24 hours):
{
"roomId": "550e8400-e29b-41d4-a716-446655440003",
"userId": "offending-user-id",
"bannedBy": "admin-user-uuid",
"reason": "Violation of community guidelines",
"expiresAt": "2026-03-23T12:00:00Z"
}
update_chat_members – Mute User / Change Role
Mute a user (requires support or admin role):
mutation MuteUser($roomId: uuid!, $userId: String!, $mutedUntil: timestamptz!) {
update_chat_members(
where: {
room_id: { _eq: $roomId }
user_id: { _eq: $userId }
}
_set: {
is_muted: true
muted_until: $mutedUntil
}
) {
affected_rows
}
}
Change a user’s role (requires admin role):
mutation SetRole($roomId: uuid!, $userId: String!, $role: String!) {
update_chat_members(
where: {
room_id: { _eq: $roomId }
user_id: { _eq: $userId }
}
_set: { role: $role }
) {
affected_rows
}
}
Valid roles: user, support, admin.
delete_chat_bans – Unban User
Requires admin role.
mutation UnbanUser($roomId: uuid!, $userId: String!) {
delete_chat_bans(
where: {
room_id: { _eq: $roomId }
user_id: { _eq: $userId }
}
) {
affected_rows
}
}
Subscriptions
chat_messages – Real-Time Messages
Subscribe to new messages in a room. Uses graphql-ws protocol over WSS.
subscription OnNewMessages($roomId: uuid!, $since: timestamptz!) {
chat_messages(
where: {
room_id: { _eq: $roomId }
is_deleted: { _eq: false }
created_at: { _gt: $since }
}
order_by: { created_at: asc }
) {
id
content
message_type
phenom_id
created_at
user {
id
username
display_name
avatar_url
}
link_preview {
url
title
thumbnail_url
}
}
}
Connection URL: wss://chat-testing.thephenom.app/api/graphql
Connection parameters:
{
"headers": {
"Authorization": "Bearer <cognito-id-token>"
}
}
Hasura Permission Matrix
| Table | Role | SELECT | INSERT | UPDATE | DELETE |
|---|---|---|---|---|---|
chat_rooms | user | All active rooms | – | – | – |
chat_rooms | admin | All rooms | – | is_active | – |
chat_messages | user | Non-deleted in joined rooms | Own messages | – | – |
chat_messages | support | All in joined rooms | Own messages | is_deleted, deleted_by | – |
chat_messages | admin | All | All | All | All |
chat_members | user | Own membership | – | – | – |
chat_members | support | All in room | – | is_muted, muted_until | – |
chat_members | admin | All | All | All | All |
chat_bans | user | – | – | – | – |
chat_bans | support | All in room | – | – | – |
chat_bans | admin | All | All | – | All |
link_previews | user | All | – | – | – |
link_previews | admin | All | All | All | All |
MCP Tool Interface
Endpoint: https://chat-testing.thephenom.app/mcp
Protocol: MCP over StreamableHTTPServerTransport (POST requests)
Authentication: Cognito agent credentials (see Admin Ops for provisioning)
The MCP server exposes 9 tools. The BACKEND_TYPE environment variable determines whether tools delegate to Hasura or Synapse.
1. chat_read_messages
Read recent messages from a room with optional pagination.
{
"name": "chat_read_messages",
"description": "Read recent chat messages from a room with optional pagination",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID to read messages from"
},
"limit": {
"type": "number",
"description": "Maximum number of messages to return (default 50)"
},
"before": {
"type": "string",
"description": "Pagination cursor — return messages created before this ISO timestamp or token"
}
},
"required": ["room_id"]
}
}
2. chat_post_message
Post a message as the AI agent.
{
"name": "chat_post_message",
"description": "Post a message to a chat room as the AI agent",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID to post the message to"
},
"content": {
"type": "string",
"description": "The message content to post"
}
},
"required": ["room_id", "content"]
}
}
3. chat_delete_message
Soft-delete a message (moderation action).
{
"name": "chat_delete_message",
"description": "Soft-delete a chat message (moderation action)",
"inputSchema": {
"type": "object",
"properties": {
"message_id": {
"type": "string",
"description": "The ID of the message to delete"
}
},
"required": ["message_id"]
}
}
4. chat_ban_user
Ban a user from a room with optional duration.
{
"name": "chat_ban_user",
"description": "Ban a user from the chat room with an optional duration",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID"
},
"user_id": {
"type": "string",
"description": "The user ID to ban"
},
"reason": {
"type": "string",
"description": "Reason for the ban"
},
"duration_minutes": {
"type": "number",
"description": "Ban duration in minutes (omit for permanent)"
}
},
"required": ["room_id", "user_id"]
}
}
5. chat_unban_user
Remove a ban from a user.
{
"name": "chat_unban_user",
"description": "Remove a ban from a user",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID"
},
"user_id": {
"type": "string",
"description": "The user ID to unban"
}
},
"required": ["room_id", "user_id"]
}
}
6. chat_mute_user
Mute a user for a specified duration.
{
"name": "chat_mute_user",
"description": "Mute a user in the chat room for a specified duration",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID"
},
"user_id": {
"type": "string",
"description": "The user ID to mute"
},
"duration_minutes": {
"type": "number",
"description": "Mute duration in minutes (default 30)"
}
},
"required": ["room_id", "user_id"]
}
}
7. chat_list_members
List room members with optional role filter.
{
"name": "chat_list_members",
"description": "List members of a chat room with optional role filter",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID"
},
"role": {
"type": "string",
"description": "Filter by role (e.g. 'admin', 'member', 'joined', 'banned')"
}
},
"required": ["room_id"]
}
}
8. chat_search_messages
Search messages by keyword (case-insensitive ILIKE on Hasura, full-text on Synapse).
{
"name": "chat_search_messages",
"description": "Search chat messages by keyword",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID to search in"
},
"query": {
"type": "string",
"description": "The search query / keyword"
},
"limit": {
"type": "number",
"description": "Maximum number of results (default 20)"
}
},
"required": ["room_id", "query"]
}
}
9. chat_get_room_state
Get room metadata and current state.
{
"name": "chat_get_room_state",
"description": "Get metadata and current state of a chat room",
"inputSchema": {
"type": "object",
"properties": {
"room_id": {
"type": "string",
"description": "The room ID"
}
},
"required": ["room_id"]
}
}
Matrix/Synapse API
Base URL: https://chat-testing.thephenom.app
Authentication: Authorization: Bearer <access_token> header. Obtain the access token via SSO login (see Mobile Integration).
Key Client-Server Endpoints
Login (SSO Redirect)
GET /_matrix/client/v3/login/sso/redirect/cognito?redirectUrl=phenomapp://chat/sso-callback
Redirects the user to Cognito for authentication, then back to the app with a loginToken.
Login (Token Exchange)
POST /_matrix/client/v3/login
Content-Type: application/json
{
"type": "m.login.token",
"token": "<loginToken from SSO redirect>"
}
Response:
{
"access_token": "syt_...",
"user_id": "@username:chat-testing.thephenom.app",
"device_id": "ABCDEFGHIJ",
"home_server": "chat-testing.thephenom.app"
}
Read Messages
GET /_matrix/client/v3/rooms/{roomId}/messages?dir=b&limit=50&filter={"types":["m.room.message"]}
Authorization: Bearer <access_token>
Response:
{
"chunk": [
{
"event_id": "$abc123...",
"type": "m.room.message",
"sender": "@user:chat-testing.thephenom.app",
"origin_server_ts": 1711100000000,
"content": {
"msgtype": "m.text",
"body": "Hello from the chat!"
}
}
],
"start": "t123-456",
"end": "t789-012"
}
Use the end token as the from parameter in subsequent requests for pagination.
Send Message
PUT /_matrix/client/v3/rooms/{roomId}/send/m.room.message/{txnId}
Authorization: Bearer <access_token>
Content-Type: application/json
{
"msgtype": "m.text",
"body": "Hello from the Phenom app!"
}
The {txnId} is a unique client-generated transaction ID (e.g., mcp_1711100000000_abc123).
Response:
{
"event_id": "$newEventId..."
}
Admin API Endpoints
These require an admin access token.
User Management
GET /_synapse/admin/v2/users/{userId}
Authorization: Bearer <admin_access_token>
Returns user profile, creation date, admin status, and device list.
Auto-Join User to Room
POST /_synapse/admin/v1/join/{roomId}
Authorization: Bearer <admin_access_token>
Content-Type: application/json
{
"user_id": "@username:chat-testing.thephenom.app"
}
Forces a user to join a room (used by the user provisioner Lambda).
Room Admin
GET /_synapse/admin/v1/rooms
Authorization: Bearer <admin_access_token>
GET /_synapse/admin/v1/rooms/{roomId}/members
Authorization: Bearer <admin_access_token>
Related Documentation
- Architecture – system design and database schema
- Admin & Operations – using these APIs for day-to-day operations
- Mobile Integration – how the mobile app consumes these APIs
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.