Skip to content
Documentation menu

Reference

REST API

Exchange an authorization code and fetch the member fields approved for your app.

Base URL and authentication

The production API base URL is https://zetapad.com. Every app completes login through these endpoints from its backend over HTTPS, including with no scopes. Client credentials alone cannot access a member: first obtain that member's one-use code through iframe consent. Do not expose client secrets or bearer tokens to the iframe.

The OpenAPI document describes login and app call endpoints. The management dashboard uses separate member APIs.

POST /v1/apps/token

Exchange a one-use authorization code obtained from iframe authenticate. Validate and consume the visitor's session-bound state challenge before making this call.

http
POST https://zetapad.com/v1/apps/token
Authorization: Basic <base64(clientId:clientSecret)>
Content-Type: application/json

{ "code": "zp_code_..." }

The JSON body must contain only code, a nonempty string of at most 128 characters. The code is valid for 60 seconds and can be used once by the registered app that received it. Invalid credentials, codes, or ended access are rejected.

Successful response (200):

json
{
  "access_token": "zp_token_...",
  "token_type": "Bearer",
  "expires_in": 900,
  "scopes": ["profile:read"]
}

Keep access_token in your backend's visitor session and record its expiry. There are no refresh tokens; use authenticate in the iframe to obtain another code.

GET /v1/apps/userinfo

Read the verified shared Zetapad member ID and approved fields:

http
GET https://zetapad.com/v1/apps/userinfo
Authorization: Bearer zp_token_...

Successful response (200) with profile:read only:

json
{
  "userId": "zp_member_...",
  "scopes": ["profile:read"],
  "username": "member_01",
  "name": "Member",
  "countryCode": "IN"
}

userId and scopes are always included, including with scopes: []. userId is Zetapad's server-generated primary member ID, shared across apps. This endpoint supplies verified identity after credential exchange. Use the server-verified userId to key experiences across apps.

With no scopes, the complete response is:

json
{ "userId": "zp_member_...", "scopes": [] }

profile:read adds username, name, and countryCode; birthdate:read adds birthdate in YYYY-MM-DD format. Unapproved fields are omitted. Every member has a username; name, country, and birthdate can be null. Usernames are unique, lowercase handles of 3–30 letters, numbers, or underscores and can change anytime. A released username can belong to another account. Use the permanent userId for saved data and the current username for display. See permissions.

Current consent and app access are checked on every userinfo read. Call it before protected app actions that rely on Zetapad access. On failure, stop the action and end the app session's Zetapad access.

Resolve identity from your server session rather than a userId in the request body. You may return approved UI fields to the browser after verification. Call scopes add a public call roster and hosted presentation after native per-call approval. App storage remains on your backend. Member and admin GraphQL APIs do not accept app credentials or app access tokens.

GET /v1/apps/calls/status

Silently check for an accepted call in this app launch's owning campus tab before asking to use it. Requires completed backend login, calls:read, current app consent, and a valid native mount; no per-call approval is needed. Send the app's server-held bearer token, with no request body or selectors:

http
GET https://zetapad.com/v1/apps/calls/status
Authorization: Bearer zp_token_...

Example response (200):

json
{ "inCall": true, "canAttach": true, "access": "approvalRequired" }

access is unavailable, approvalRequired, or approved. An unavailable result has both booleans false; accepted participation has both true. Pending invitations and calls in other tabs are unavailable. The response contains only these three fields and creates no grant, prompt, or presentation. Invalid login, revoked consent, or stale mounts return errors rather than false availability.

Offer Use current call in this app when canAttach is true. On the member's choice, request POST /v1/apps/calls/attach; it independently rechecks access and requests native approval when needed. Remembered approved access still requires attachment and presentation preparation. See the availability contract and tested example.

Error responses

json
{
  "error": {
    "code": "ACCESS_REVOKED",
    "message": "App access has ended. Authenticate again to continue."
  }
}
HTTP statusCodeMeaning
400BAD_USER_INPUTInvalid JSON token-exchange body or unsupported fields
401INVALID_CLIENTClient ID or secret could not be verified
401INVALID_TOKENCode or access token is invalid, expired, or already used
403ACCESS_REVOKEDMember consent or issued access ended
403APP_UNAVAILABLEThe app can no longer be launched or used in this context
403FORBIDDENA required call scope or permission is missing
503INTERNAL_SERVER_ERRORTemporary app-service failure

Success and error responses use Cache-Control: private, no-store. Do not cache them or log credentials. For recovery steps, see errors and troubleshooting.