Customer access as MarkdownUse a clean Markdown version of this page with an agent or local tooling.
Customer access
Give each customer the correct project or location scope through an embedded Signal application or a short-lived link to hosted Signal.
Choose embedded or hosted access
Both access modes use an embedded identity and its project or location grants. Choose where the customer should work.
Embedded accessMount Signal inside your product with a short-lived embed session. Your backend mints the token, and the browser receives only that token. Embed roles are
viewer or editor.Hosted accessCreate a redirect login link when the customer should open the hosted Signal application. The resource package must enable
pricing.frontend_delivery_enabled.Origin configurationFor embeds, add each HTTPS host-page origin to the issuing API key's
allowed_origins. The same allowlist validates an optional hosted-login return_url.Keep the API key server-sideCreate embed sessions and login links from your authenticated backend. Never place a Signal API key in browser code or loader options.
Provision identities and access grants
Use a workspace-scoped key with identities:manage. The external user ID is unique within the workspace, and repeating the request updates the same identity.
Upsert identity and grant accesscURL
# Upsert an identity using your stable user ID.
curl --request POST \
--url 'https://api.signal.ceyo.ai/v1/embedded-identities/customer-user-42' \
--header "Authorization: Bearer ${SIGNAL_API_KEY}" \
--header 'Content-Type: application/json' \
--data '{
"email": "user-42@example.com",
"name": "User 42"
}'
# Grant access to one project.
curl --request POST \
--url 'https://api.signal.ceyo.ai/v1/embedded-identities/customer-user-42/projects/customer-project/access' \
--header "Authorization: Bearer ${SIGNAL_API_KEY}" \
--header 'Content-Type: application/json' \
--data '{ "role": "viewer" }'Project grantGrants project access. It also applies when issuing a location-scoped session beneath that project.
Location grantUse the nested
/projects/{project_id}/locations/{location_id}/access path to restrict access to one location.Granted-location portfolioMint with
location_scope: "granted" and no location_id to expose active direct location grants in one project. Signal resolves them live, preserves each location's role, and ignores project grants for this scope. Revoking one grant removes only that location. The embed exposes Overview and Locations, not project-wide routes.RolesGrants accept
viewer, editor, or admin. Embed sessions expose only viewer or editor; an admin grant resolves to editor in the iframe.LifecycleSet an identity to
disabled to block new access and revoke its active embed sessions. Delete a grant to remove that resource scope.Optional inline embed provisioning
POST /embed/sessions can atomically upsert an identity, create a viewer or editor grant, and issue its first session through the provision object. With granted scope, use provision.location_grants to ensure one to 100 direct grants atomically. This requires a workspace-scoped key with both embed_sessions:create and identities:manage.Provision granted locationsJSON
{
"external_user_id": "regional-manager-42",
"project_id": "customer-project",
"location_scope": "granted",
"provision": {
"location_grants": [
{ "location_id": "store-amsterdam", "role": "editor" },
{ "location_id": "store-utrecht", "role": "viewer" }
]
}
}Create redirect login links
Use a key with login_links:manage. The identity must be active and already have access to the requested project or location, and the assigned package must enable customer access.
Create a hosted login linkcURL
curl --request POST \
--url 'https://api.signal.ceyo.ai/v1/login-links' \
--header "Authorization: Bearer ${SIGNAL_API_KEY}" \
--header 'Content-Type: application/json' \
--data '{
"external_user_id": "customer-user-42",
"project_id": "customer-project",
"expires_in": 900
}'Lifetime
expires_in defaults to 900 seconds and accepts 60 to 3,600 seconds.One-time useSend the returned
login_link.url directly to the intended customer. Redemption marks it used, so it cannot be redeemed again.DestinationOmit
redirect_path to open the selected resource. Custom values must be safe paths within hosted Signal, not absolute URLs.Return URLAn optional
return_url must use HTTPS and an origin listed in the issuing API key's allowed_origins.Inspect or revokeUse
GET /login-links/{login_link_id} to inspect status. Use DELETE on the same path to revoke a link while it is still pending. Treat the returned URL as a secret.Manage session renewal and revocation
Embed sessions default to 3,600 seconds and accept a TTL from 60 to 86,400 seconds. Refresh them through your backend; never expose the API key to the browser.
Rotate an embed sessioncURL
curl --request POST \
--url 'https://api.signal.ceyo.ai/v1/embed/sessions/refresh' \
--header "Authorization: Bearer ${SIGNAL_API_KEY}" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: ${UNIQUE_REQUEST_ID}" \
--data '{
"session_token": "${CURRENT_SESSION_TOKEN}",
"ttl_seconds": 3600
}'Renew before expiryImplement the loader's
onTokenExpired callback. Return the replacement token, or call embed.updateToken() after your backend refreshes it.RotationA successful refresh exchanges the current token for a replacement. The exchanged token no longer authorizes embed API requests.
Access checksRefresh and embed requests recheck the identity, resource, grant, role, and issuing API key. If refresh is rejected, mint a new session only after your application confirms the user still has access.
Immediate revocationDisable the identity, revoke or change its grant, or revoke the issuing API key. Active embed requests then fail their live access check.
Use unique idempotency keysSession create and refresh requests require an
Idempotency-Key. Reuse it only when retrying the same operation with the same request body.