Skip to content

Invite payload reference

A WorkspaceInvitePayload is what travels from inviter to recipient. Two on-wire representations of the same JSON:

  • URLhive://invite/<base64url-of-payload>
  • Short code — hyphen-grouped base64url, no scheme prefix (so it pastes cleanly into chat/voice)

Schema

{
  "workspaceID": "00000000-0000-0000-0000-000000000000",
  "workspaceName": "Hive architecture pass",
  "relayEndpoint": "https://rendezvous.example.com",
  "relayTokenEnvVar": "HIVE_RELAY_TOKEN",
  "relayAuthHint": "Set HIVE_RELAY_TOKEN in your shell before launching Hive.",
  "inviterAccountID": "00000000-0000-0000-0000-000000000000",
  "inviterDeviceID": "00000000-0000-0000-0000-000000000000",
  "inviterDisplayName": "Alice",
  "inviterSigningPublicKey": "<base64 32-byte Ed25519>",
  "issuedAt": "2026-05-30T12:00:00Z",
  "expiresAt": "2026-05-30T13:00:00Z",
  "passcode": "rosebud"
}
Field Required Notes
workspaceID yes UUID of the workspace to join
workspaceName yes Display label for the accept sheet
relayEndpoint no If present, recipient auto-configures transport.rendezvous.endpoint
relayTokenEnvVar no Env var the recipient should consult for bearer token
relayAuthHint no Human-readable note rendered in the accept sheet
inviterAccountID yes UUID, joins recipient's WorkspaceMember roster
inviterDeviceID yes UUID, used to look up signatures from the inviter's device
inviterDisplayName yes Shown in the accept sheet
inviterSigningPublicKey yes 32-byte Ed25519, raw bytes base64-encoded
issuedAt yes ISO-8601
expiresAt no ISO-8601; recipient rejects if Date.now > expiresAt
passcode no Short string; recipient must paste it separately to accept

URL encoding

The URL form is:

hive://invite/<base64url-no-padding>

The payload-as-JSON is encoded with JSONEncoder.outputFormatting = [.sortedKeys] + ISO-8601 dates, base64url-encoded (- for +, _ for /, no = padding). Wrapped to be URL-safe; survives most chat clients without further escaping.

Short code

Same bytes as the URL form, hyphenated every 4 characters:

eyJ3-b3Jr-c3Bh-Y2VJ-RCI6-IjEy-MzQt-NTY3-OC05-MGFi-Y2RlZi0xMjM0LTU2N

The recipient can paste the URL OR the bare base64url OR the hyphenated short code — WorkspaceInvitePayload(string:) accepts all three.

Passcode handling

Passcodes are embedded in the payload's signed bytes. That means:

  • An attacker who captures only the URL cannot verify the passcode without first decoding it — but they can decode it, since the payload is just signed not encrypted.
  • The passcode's value lives in the same artifact as the rest of the payload.

That's why the recommendation is to share the passcode on a separate channel — if Alice DMs the URL on Slack and texts the passcode, an attacker would have to compromise both channels to redeem.

For high-stakes deployments, deliver the invite over a channel that's already authenticated end-to-end (Signal, age-encrypted file).

Validation rules

The recipient's Hive enforces:

  1. isCurrentlyValid()Date.now <= expiresAt (or no expiry).
  2. If passcode is set, recipient must paste a matching string in the accept sheet.
  3. Future envelopes signed by inviterSigningPublicKey verify against the embedded key.

What the recipient's Hive does not verify:

  • Whether the inviter has the authority to invite — that's enforced workspace-side by the authz evaluator at envelope acceptance time.
  • Whether the relay endpoint is reachable — pre-flighted lazily on first publish.

See hive-core (invite types) for the canonical implementation.