PassPort app launch & app-entry¶
When a user opens your registered application, PassPort decides where it should land based on that user’s account state — a not-yet-set-up account can be routed to an onboarding screen, an active account straight into the app. This page covers declaring your app’s launch surface at registration and resolving the entry point at runtime.
All paths are under the public gateway at https://api.flexgalaxy.ai.
Declare your launch surface when you register¶
Register (or update) a service with POST /developer/v1/services. The service
manifest’s surfaces.app_launch describes how your app is opened. Paths are
relative — the platform resolves them against your app origin.
{
"surfaces": {
"app_launch": {
"allowed_redirect_paths": ["/", "/auth/callback"],
"launch_path": "/",
"required_action": "sampleApp:Open",
"resource_frn_pattern": "frn:${account_id}:sample-app:app/*",
"onboarding_entry_url": "/welcome"
}
}
}
allowed_redirect_paths— the permitted post-sign-in return paths. Your app’s homepage is derived from the first entry that is not a/passport/…callback.launch_path/required_action/resource_frn_pattern— the launch target and the authorization action + resource pattern checked when the app opens.onboarding_entry_url(optional) — a distinct entry for accounts that are not yet active (see below). Omit it and every account opens at the homepage.
A newly registered service is reviewed and approved before it becomes launchable; until then app-entry resolution will not find an active application for it.
Resolve the entry point at runtime¶
On Open, call:
POST /passport/v1/app-entry/resolve
{ "appId": "<application id>", "accountId": "<account uuid>" }
Both fields are required. Note that the PassPort surface is camelCase, unlike the snake_case organization and account APIs.
accountId is not taken on trust: PassPort verifies that the account holds an
active installation of the application, that your token was issued in that
account’s organization realm, and that you are an assigned workforce member of
that account, before it resolves anything.
The response tells you where to send the authenticated principal, keyed off that account’s lifecycle state:
{
"appId": "<application id>",
"accountId": "<account uuid>",
"entryKind": "ONBOARDING",
"deepLink": "/welcome?account_id=<account uuid>",
"lifecycleStatus": "PLACEHOLDER",
"displayName": "…"
}
Account lifecycle status |
|
Where |
|---|---|---|
|
|
the app’s |
|
|
the app homepage / launch path |
no lifecycle record (an ordinary, non-onboarded account) |
|
the app homepage / launch path |
|
— |
|
deepLink always carries the resolved account as an account_id query
parameter, appended with & when the configured URL already has a query string.
lifecycleStatus is omitted for an account with no lifecycle record.
This is a signed-in (workforce / session) call — drive it from your app’s
authenticated front end. An AK/SK service credential is rejected with 401.
Look up an application’s public metadata with:
GET /passport/v1/applications/{appId}
Orgs: org-scoped entry for org-shaped apps¶
Some registered applications are org-scoped: a tenant enters through an enterprise org rather than through an account, and the app serves one site per org. A deep link to such an app pins the org, and PassPort resolves an entry for that org and nothing else — there is no fallback to another org the caller also belongs to, and no console/StartPoint access is reachable from an app-entry flow.
The resolve call takes orgId instead of accountId — exactly one of the two
is required (400 entry_context_required otherwise):
POST /passport/v1/app-entry/resolve
{ "appId": "<application id>", "orgId": "<org uuid>" }
Semantics:
The org is pinned. The entry is resolved through the org’s management account, and the returned deep link is built only from the requested org.
The same guard chain as account entry applies: the application must be active, the app must have an active installation on the org’s management account, your token must be issued in the org’s entry realm — the realm the public discovery endpoint below returns, which is the platform realm
flexgalaxyfor every org today — and you must be an assigned workforce member of the management account. The context in the request is never trusted as an unchecked claim.The management account’s lifecycle status maps to
entryKindexactly as in the table above; aCLOSEDorg has no entry (409 account_closed).deepLinkis the org’s registered site URL with the org id substituted for the{orgId}placeholder — it lands you inside the org’s site.
An org launch shape is declared at registration: the app registers a site
URL template containing exactly one {orgId} placeholder. An org entry cannot
resolve without it — a malformed registration is a clean
403 application_unavailable, never a silent fallback to an account-scoped or
cross-org entry.
The response carries the resolved context:
{
"appId": "<application id>",
"accountId": "<management account uuid>",
"orgId": "<org uuid>",
"entryKind": "APP",
"deepLink": "https://site.example/orgs/<org uuid>",
"lifecycleStatus": "ACTIVE",
"displayName": "…"
}
orgId is present only on the org-scoped path; accountId is the management
account the entry was resolved through.
Feed the org picker: orgs you can enter¶
POST /passport/v1/app-entry/orgs
{ "appId": "<application id>" }
returns the orgs the caller may enter this application through — assigned orgs only (the workforce assignment projection), filtered to orgs that carry an active installation on their management account, and bound to the caller’s own token realm:
{
"orgs": [
{ "orgId": "<org uuid>", "orgName": "…", "issuer": "https://…/realms/<realm>" }
]
}
A caller assigned to exactly one such org can be sent straight through the
org-scoped resolve; with several, the front end renders a picker. issuer is
the entry realm’s token issuer (the platform realm’s, for every org today), so
the feed is self-sufficient — a front end never computes realm data.
Public pre-auth discovery for deep links¶
GET /passport/v1/app-entry/orgs/{orgId}
returns the realm an unauthenticated caller must sign in to before resolving an entry for the org pinned by a deep link:
{
"orgId": "<org uuid>",
"orgName": "…",
"idcRealmName": "flexgalaxy",
"issuer": "https://auth.flexgalaxy.ai/auth/realms/flexgalaxy"
}
The idcRealmName field carries the org’s entry realm — the realm the caller
signs in through; that is the platform realm flexgalaxy for every org today.
(The field name is retained for contract compatibility.)
This endpoint is public by design — it is login-enablement data (the org id
the link already carries, the org’s display name, and its entry realm), not a
membership claim. It returns 404 org_not_found when the org is unknown: a deep
link to such an org is not a login anyone can complete.
See also¶
Account lifecycle status — the status values that drive this routing
CLI reference —
fgai passport app-entry-resolve,fgai developer create