Evenements WebSocket
Connection
Human WebSocket
GET wss://api.hashee.ai/ws/humanAfter upgrade, send auth within 5 seconds:
{ "type": "auth", "token": "<access_token>" }Agent WebSocket
GET wss://api.hashee.ai/ws/agent?agent_id={agentId}After upgrade, send auth within 5 seconds:
{ "type": "auth", "token": "hsk_...", "agent_id": "{agentId}" }Auth Response
Success:
{ "type": "auth.ok" }Failure:
{ "type": "auth.error", "reason": "invalid_token", "message": "Token expired", "i18n_key": "error.auth.expired"}Client-to-Server Frames
auth.renew
Renew the access token on an existing connection. Send after refreshing the JWT via REST:
{ "type": "auth.renew", "access_token": "new_jwt..." }Server-to-Client Events
Message Events
message.new
A new message in a conversation:
{ "type": "message.new", "conversation_id": "uuid", "message_id": "uuid", "sender_id": "uuid", "sender_type": "human", "content_type": "text", "encrypted_payload": "base64...", "conversation_seq": 42, "created_at": "2026-01-01T00:00:00Z"}message.ack
Acknowledgment that a sent message was received by the server.
message.read
A participant read messages up to a certain sequence number.
message.recalled
A message was recalled by the sender:
{ "type": "message.recalled", "message_id": "uuid", "conversation_id": "uuid", "recalled_by": "uuid"}message.status_updated
Message delivery status changed.
message.pinned
A message was pinned in a group.
Stream Events
stream.start
An agent began streaming a response.
stream.delta
A chunk of streamed content:
{ "type": "stream.delta", "conversation_id": "uuid", "encrypted_payload": "base64..."}stream.done
Stream completed with the full encrypted payload for persistence.
stream.abort
Stream was cancelled by the agent.
stream.error
Stream timed out or hit a limit.
Relationship Events
relation.established
A new user started using the agent:
{ "type": "relation.established", "payload": { "user_id": "uuid", "display_name": "Alice", "avatar_url": "https://...", "language": "en", "referral_source": "invite_link", "public_key": "base64..." }}The SDK automatically caches the public_key from this event.
relation.terminated
User disconnected from the agent:
{ "type": "relation.terminated", "payload": { "user_id": "uuid" } }relation.suspended
User was suspended by the creator:
{ "type": "relation.suspended", "payload": { "user_id": "uuid" } }relation.restored
User was restored by the creator:
{ "type": "relation.restored", "payload": { "user_id": "uuid" } }Artifact Events
artifact_response
User responded to an artifact (form submission, button click):
{ "type": "artifact_response", "payload": { "conversation_id": "uuid", "message_id": "uuid", "ref_artifact": "artifact_id", "ref_action": "submit", "based_on_revision": 1, "values": { "name": "My Project" } }}artifact_update
An agent updated an artifact (WebSocket delivery to human clients).
artifact.expired
An artifact’s TTL expired:
{ "type": "artifact.expired", "payload": { "conversation_id": "uuid", "message_id": "uuid", "artifact_id": "uuid" }}Agent Events
agent.governance
Agent governance status changed (WebSocket only, not delivered via webhook):
{ "type": "agent.governance", "payload": { "agent_template_id": "uuid", "governance_status": "suspended", "reason": "Policy violation" }}If status is suspended or banned, the WebSocket connection is terminated.
agent.status
Agent online/offline status changed.
agent.typing
Agent is typing.
Reaction Events
reaction.update
Reactions on a message changed (aggregate state):
{ "type": "reaction.update", "payload": { "message_id": "uuid", "reactions": [ { "emoji": "thumbsup", "count": 3, "user_ids": ["uuid1", "uuid2", "uuid3"] } ] }}Group Events
group.updated
Group info changed (name, avatar, settings):
{ "type": "group.updated", "payload": { "conversation_id": "uuid", "changes": { "name": "New Group Name" } }}Session Events
auth.expiring
Advisory: access token is about to expire. Client should refresh via REST and send auth.renew:
{ "type": "auth.expiring", "expires_in_seconds": 60 }session.invalidated
Server terminated the session (device kicked, password changed, etc.):
{ "type": "session.invalidated", "payload": { "reason": "device_removed", "message": "Session terminated", "i18n_key": "error.session.invalidated" }}error
Generic WebSocket error:
{ "type": "error", "payload": { "code": "RATE_LIMITED", "message": "Too many requests", "i18n_key": "error.rate_limited" }}Event Delivery by Transport
| Event | WebSocket | Webhook |
|---|---|---|
message.new | Yes | Yes |
relation.established | Yes | Yes |
relation.terminated | Yes | Yes |
relation.suspended | Yes | Yes |
relation.restored | Yes | Yes |
artifact_response | Yes | Yes |
agent.governance | Yes | No |
reaction.update | Yes | No |
group.updated | Yes | No |
artifact.expired | Yes | No |
session.invalidated | Yes | No |
auth.expiring | Yes | No |
Long Polling delivers the same event set as Webhook.
Next Steps
- REST Endpoints — HTTP endpoint reference
- Error Codes — Error code table
- Streaming — SDK streaming guide