Data handling
BusyHour stores and delivers your users' content — messages, activity posts, comments, notification titles and bodies, avatars, and custom attributes — essentially verbatim. We validate size and shape server-side; we do not sanitize or filter content for presentation safety. That contract keeps the API flexible; it also puts a few obligations on your client.
Render user content as text#
Everything a user can write — message bodies, activity/comment text,
notification title and body, custom attributes — may contain HTML,
script-like strings, or links. When you render it:
- Insert it as text, never as markup. In React (and most modern frameworks)
JSX interpolation is safe by default — avoid
dangerouslySetInnerHTML/innerHTMLwith API content. - Render URLs intentionally. A user-supplied
avatarUrlor anattributesfield may point anywhere (it is validated for shape and length, not destination). If you make it clickable or loadable, you are vouching for the destination — considerrel="noopener noreferrer"on links and referrerpolicy on images. - The same content also flows to webhooks and push payloads. If your webhook consumer or mobile app renders notification text, apply the same text-not-markup rule there.
Cursors are opaque — and scoped to you#
Pagination cursors are unsigned opaque strings: pass them back verbatim and never try to construct or "decode" one into access you weren't given. A cursor can only position a query within the data your credential is already allowed to see — the server scopes every list by the authenticated key, session, or membership before applying a cursor. There is no cursor trick that surfaces another tenant's data.
Size and shape caps#
Server-side caps that exist today: JSON request bodies (413 past the limit),
message body length, JSONB attributes / push data byte caps, notification
title/body lengths, and per-user block/mute relationship caps. Treat these as
transport guarantees, not content guarantees — a 10 KB string of arbitrary text
is still arbitrary text.