Skip to content

Team rooms

Rooms are team chat spaces inside your workspace, separate from visitor Chats. Everyone in them is a teammate holding a seat in your workspace — visitors never see a room, and the support bot has no access to one.

Every role in a workspace (operator and up) can read and post in rooms.

Channels are named rooms anyone in the workspace can find and join. Create one from the Rooms page with a name, an optional topic, an optional emoji icon and color, and a minimum level.

Direct messages start from New message (on the Rooms page, or the + beside Direct messages in the sidebar). Pick up to 8 teammates — a DM holds between 2 and 9 people including you. DMs are:

  • private to their participants — nobody else can find, search, or join them, and they don’t have a level gate;
  • deduplicated by participant set, so opening a DM with the same people always lands you back in the same conversation;
  • not renamable and not deletable as a room.

The sidebar on every room page lists your channels and your DMs with unread counts, so you can hop between conversations without going back to the index. The Rooms page also has a search box that searches your rooms and their messages.

Channels are open: pick one from the Rooms page and hit Join room. You need to have joined before you can read or post. Leave room any time; rejoining later is always allowed and your old messages stay.

A channel’s Minimum level setting gates it by workspace seat:

  • Everyone (the default)
  • Member +
  • Admin +
  • Owner only

Someone below the level doesn’t just get “access denied” — the room is absent from their room list, their search results, their unread counts, and their notifications. An “Admin +” room is a safe place for admin-only coordination.

You can’t set a level above your own seat. Gated rooms show a 🔒 chip in the room list.

Messages appear for everyone in the room in real time. A message can be up to 4,000 characters and supports markdown. Enter sends, Shift+Enter starts a new line.

  • Replies — reply to a specific message and it shows a quoted line above yours.
  • Reactions — react with an emoji; clicking your own reaction again removes it.
  • Attachments — 📎, drag files into the composer, or paste a screenshot. Same rules as the chat widget: images (PNG, JPEG, WebP, GIF) up to 15 MB, documents (PDF, TXT, CSV, Markdown, RTF, DOC/DOCX, XLS/XLSX, PPT/PPTX) up to 25 MB, at most 5 attachments per message. Images render inline; documents render as download links.
  • Link previews — the first few links in a message get a preview card once it’s been fetched.

Type @ in the composer (at the start of a line or after a space) to pick a room member from a typeahead; @everyone is one of the options it offers. A mention is @ followed by a member’s display name, matched case-insensitively and bounded on both sides — so @Ann matches neither a@ann.test nor @Annabel. Names with spaces work, and the longest matching name wins, so @Ann Smith credits Ann Smith rather than Ann.

Mentioned people see their name highlighted and their notification says you mentioned them, so it stands out from ordinary room traffic.

@everyone follows the same boundary rules and notifies the whole room. It’s a flag on the message, not a mention of each person individually.

You can edit your own messages — the key in an empty composer opens your last one for editing. Edited messages show a small “edited” marker, and the edit is pushed to everyone with the room open. Mentions and link previews are re-extracted from the new text, and editing never re-notifies anyone.

You can delete your own messages. Someone with room-management access can delete any message in the workspace’s rooms. A room’s creator can rename, re-topic, or delete their own room; workspace admins and owners can manage any room.

An unread badge is a red count on the room in the list and in the sidebar, plus a red dot on Rooms in the workspace sidebar. Unread counts everything posted since you last read the room, except your own posts — with one exception: messages posted by your own incoming webhook keys do count as unread, because a script posting on your behalf is still something you haven’t seen.

Mute is per-room, from the notifications menu in the room header: 1 hour, 8 hours, 24 hours, or until you unmute. Muting silences push notifications only — the messages still arrive, the room still updates live, and unread counts still climb. A muted room shows a 🔕 marker.

An incoming webhook lets a script post a message into a room — CI results, deploy notifications, alerts.

Create one on the room’s Settings → Webhooks tab: give the key a name (that’s the name messages will display under) and it’s created immediately. Each key gets its own page with the full key (masked until you press Reveal), the ingest URL, a ready-made curl example, and buttons to rotate, disable, or delete it.

Terminal window
curl -X POST \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: my-unique-id-001' \
-d '{"body": "hello from a script", "sender": "my-bot"}' \
https://vroxy.ai/wh/in/YOUR_KEY

Request fields:

Field Meaning
body The message text — markdown and @-mentions work. Required. Slack-style text is accepted as an alias; body wins if you send both.
sender Per-request display-name override, up to 120 characters (aliases: name, username). Falls back to the key’s name, then the key creator’s account name.
room Post into a different room by its id (aliases: room_hashid, channel). Only rooms the key’s creator has joined and can see — never a DM.
idempotency_key Retry-safe deduplication, up to 255 characters. A replay answers 200 with the original message id instead of posting a duplicate. The Idempotency-Key header wins over the field.

Responses: 201 with {"message_id": "…"} on success, 404 for an unknown, disabled, or deleted key (all three answer identically, so the key’s existence never leaks), 422 for a missing or over-long body, and 429 when rate-limited — 60 posts per minute per key by default.

Things to know:

  • The path token is the authentication. There are no headers to set and no CSRF token. Treat the URL like a password: anyone holding it can post into that room.
  • Permissions resolve against the seat of the person who created the key, so if they leave the room (or the workspace) their keys stop working.
  • Webhook messages display under the key’s name with a 🔗 badge, and notify everyone in the room — including the key’s creator.
  • Rotate mints a fresh key and the old one stops working immediately.

An outgoing webhook POSTs every member-posted message in the room to a URL of yours. Add one on the same Settings → Webhooks tab.

The body is JSON:

{ "event": "message_created", "room": { }, "message": { } }

and it carries a signature header computed over the raw request body with the hook’s signing secret:

X-Vroxy-Signature: sha256=<HMAC-SHA256 of the body>

Verify it before trusting the payload. The webhook’s page shows the secret (masked until revealed), the payload shape, and a Ruby verification snippet.

Two behaviors to plan around:

  • Loop guard. Messages that arrived via an incoming webhook are never fanned out to outgoing webhooks. Without that, an incoming hook feeding an outgoing hook that posts back is a message storm.
  • Auto-disable. A hook that fails 20 times in a row disables itself, so a dead endpoint doesn’t burn a delivery attempt per message forever. The room’s webhook list shows the consecutive-failure count; fix the endpoint and re-enable it.