Security and privacy

How Fishcamp protects sign-in, secrets, invites, guests, agents, audio and transcripts. Hashed tokens, deny-by-default rooms, no stored audio and HTTPS.

Updated

Signing in

  • You sign in with Google or with a 6-digit code sent to your email. There are no Fishcamp passwords to leak or reuse.
  • A code works for 10 minutes, only the latest one is valid, and it allows 5 attempts. After three codes in 10 minutes you have to wait.
  • Codes are stored as keyed hashes, and asking for one gives the same answer whether or not the email has an account.

Secrets are stored as hashes

API keys (cwk_…), incoming webhook URLs (whk_…) and email invite links (inv_…) are random secrets. Fishcamp shows each one once, when it's created, and stores only a hash of it. Lists show what each secret is for, never the secret itself. If one leaks, revoke it and create a new one.

Secrets Fishcamp has to use are encrypted

New in November 2026

An AI agent's webhook signing secret (whsec_…) and an OpenSync space token (osk_…) are stored encrypted, because Fishcamp needs them to sign deliveries and to save notes. The API never returns them: the webhook secret is shown once, when the agent is created or the secret is rotated, and admins see only the last four characters of the OpenSync token.

New in November 2026

Invite links (fishcamp.space/join/…) and meeting links (fishcamp.space/m/…) are made to be passed around, so they can be copied again later. Treat them like keys to a door:

  • An invite link lets anyone who has it join as a Member, until it expires (30 days by default), reaches its limit of uses or an admin turns it off. Links to a private channel only show up for admins who are in it.
  • A meeting link only opens one channel's audio room, and only while someone from the workspace is in it. New link and Turn off link close it at once and take the guests out of the room.
  • Their pages aren't indexed by search engines, and they don't pass their address on to the sites they link to.

Email invites belong to one address

  • An email invite only works for the address it was sent to: someone signed in with a different email can't accept it.
  • It expires after 7 days, and admins can revoke it any time before it's accepted.
  • Sending a new invite to the same address replaces the old link.

Workspaces and channels deny by default

  • Every request is checked against the workspace. You only reach workspaces you're a member of, and IDs from another workspace answer "not found".
  • Private channels and direct messages are invisible to outsiders. People who aren't in them get "not found", not "forbidden", so the API never confirms they exist.
  • Live updates follow the same rules. The app only receives messages, pills and audio room changes for the channels you can see.
  • Audio rooms: a token to join is only issued to someone who can see the channel, it's short-lived, and it only allows the media the channel has switched on.
  • API keys never act as admins. Even a key an admin created can't invite people, change roles, archive or rename channels, delete other people's messages, or manage invite links, webhooks, API keys, AI agents and integrations, so an agent can't change who has access. It edits and deletes only the messages it posted, and every read needs its read scope.

Guests only get the call

New in November 2026

People who join with a meeting link have no account and no access to the workspace:

  • They get the audio room of one channel, and only while someone from the workspace is in it: Fishcamp checks it as they connect, and when the last person from the workspace leaves, the meeting ends for them. They can't read messages, see other channels or list people.
  • Their token opens the call and, when the channel has transcription on, sends their own audio to be transcribed. The rest of the API refuses it, and guests can't send data messages in the room.
  • A room takes at most 20 guests. Anyone in the channel can remove one, and guests always show a Guest label.
  • When a guest spoke, Dcision never sends the transcript to AI agents on its own: a person confirms first.

AI agents stay in their channels

New in November 2026
  • An agent's API key only reaches the agent's channels, in the REST API and the MCP server. See API keys.
  • Agents follow the admin behind them. An admin can only connect an agent to channels they can see, and an agent only gets events while its key is active and that admin is still in the workspace and can see the channel.
  • Webhook deliveries are signed with HMAC-SHA256 and a timestamp, so an agent can check they come from Fishcamp and refuse old ones. See Agent webhooks.
  • Fishcamp only calls public https addresses for agent webhooks and OpenSync. Addresses with a user or password, local names and private networks (IPv4 and IPv6) are refused. The address is checked as Fishcamp connects, so a DNS change can't send a call into a private network, and redirects aren't followed.
  • The OpenSync token stays with its space. Changing the space or the OpenSync address needs the token pasted again.

Audio is never stored

  • Audio rooms aren't recorded.
  • With transcription on, speech is turned into text as it happens and only the text is kept. Everyone in the room sees Transcribing while it runs.
  • Audio and video travel encrypted between browsers and the media server, as WebRTC requires (DTLS-SRTP).

HTTPS everywhere

The app (fishcamp.space), the API (api.fishcamp.space) and these docs (docs.fishcamp.space) are only served over HTTPS. The app and the docs also send Strict-Transport-Security, so browsers never fall back to plain HTTP.

Smaller things that matter

  • Images from webhooks aren't loaded. A webhook's avatar_url is ignored, because loading images from other sites would reveal readers' IP addresses to them.
  • Links open safely. Links in messages open in a new tab without passing on where you came from.
  • Rate limits slow down guessing and floods. See REST API → Rate limits.
  • Messages from software are labeled. Webhook messages show an App label and API key messages an AI label, so nobody mistakes them for a person.

On this page