Skip to content
Documentation menu

Reference

Iframe protocol

The version 2 postMessage contract for readiness and code-only authorization.

Transport and trust

Use window.parent.postMessage with an exact trusted Zetapad origin. Install a message listener before sending ready. Verify event.source === window.parent and the exact event.origin, then pin the responding parent origin after the readiness handshake.

Production parents are https://zetapad.com and https://www.zetapad.com. Use a fresh request ID for each request. Untrusted or malformed messages receive no response.

Version 2 supports only ready and authenticate. Member IDs and profile fields are available through backend REST authentication, including for apps with no scopes.

Request envelope

json
{
  "channel": "zetapad",
  "version": 2,
  "requestId": "unique-id",
  "method": "ready",
  "params": {}
}

channel must be zetapad, version must be 2, and requestId must be a nonempty string of at most 128 characters. params must be an object. Unknown top-level fields, method names, and extra params are rejected. The app identity and scopes come from the Zetapad registration; requests cannot override them.

See the JSON Schema for machine-readable message shapes.

ready

Call with params: {} after the iframe loads. A successful result is:

json
{ "launchId": "zp_launch_...", "appId": "zp_app_..." }

Keep the launch ID for subsequent calls. It belongs to the currently mounted room; it is not an app login token. Launches expire after one hour, and authentication may extend the stored launch lifetime. Reopen the room when a launch is stale or expired.

Zetapad shows retry controls after 15 seconds without a valid readiness handshake. Install the listener and send ready promptly.

authenticate

Call after ready with the current launch ID and a backend-generated state challenge:

json
{ "launchId": "zp_launch_...", "state": "random-session-bound-challenge" }

launchId is a nonempty string of at most 128 characters and must match the current launch. state must be a nonempty string of at most 256 characters. A successful result is:

json
{
  "code": "zp_code_...",
  "expiresIn": 60,
  "state": "random-session-bound-challenge"
}

The member grants every registered scope or cancels. Saved consent is reused when it remains valid. Wait for the pending consent or authentication request rather than starting another one. On cancellation, the member receives CONSENT_DENIED and Zetapad closes the room.

The result contains only code, expiresIn, and state. A successful reply means the member authorized a code; your app is not logged in until its backend completes verification.

Your backend must validate and consume the echoed state against the same visitor session before exchanging the code. The code expires after 60 seconds and can be exchanged once by its registered app using its client ID and secret. REST userinfo then returns the shared server userId, granted scopes, and approved fields. This flow is required even with zero scopes. See authentication.

Response envelope

Success replies contain exactly one result; failure replies contain exactly one error. Both echo channel, version, and requestId:

json
{
  "channel": "zetapad",
  "version": 2,
  "requestId": "unique-id",
  "error": { "code": "STALE_LAUNCH", "message": "Complete the ready handshake for this room first." }
}

Correlate each reply with its pending request ID and ignore replies for unknown requests. Handle errors by their stable code; messages explain the issue to the developer. See errors and troubleshooting for recovery actions.