Integrate an external app with AK/SK

This is the end-to-end guide for integrating an external application with the FlexGalaxy.AI platform using a service access key (AK/SK) only — no interactive user session, no admin console, and no self-registration. If you are building a portal or backend that provisions accounts, authors policy, checks authorization, and manages users on behalf of your customers, this is the whole path.

The integration model

Your application is a service principal. During onboarding you are issued one service-user access key (an access-key id + secret). From then on you sign every request with FGAI-HMAC-SHA256 against the public API gateway at https://api.flexgalaxy.ai, under the /identity/v1/…, /accounts/v1/…, /organizations/v1/… capability paths.

Note

There is no interactive step in this model. You do not capture a human’s login, you do not call the browser/console gateway, and you do not self-register the app (app registration is done once during onboarding). One credential signs everything below.

Your key is bound to one account. Every call is evaluated in that account’s scope: you can only read and change resources in the account your key belongs to. Cross-account access is a separate, explicit delegation feature — not something a single key does implicitly.

1. Get your credential

You receive a service-user access key during onboarding. To issue additional keys or rotate your own, see [CLI & service authentication](https://docs.flexgalaxy.ai/dev/dotid/cli-authentication/). A key is an access-key id (e.g. AKIA…) and a secret; temporary (STS) keys start with ASIA… and also require a session token.

2. Sign a request (FGAI-HMAC-SHA256)

Every request carries these headers:

Header

Value

Authorization

FGAI-HMAC-SHA256 Credential=<access-key-id>/<date>/<region>/<service>/fgai4_request, SignedHeaders=<h1;h2;…>, Signature=<hex>

X-FGAI-Date

Request timestamp, yyyyMMddTHHmmssZ (UTC)

X-FGAI-Content-SHA256

Hex SHA-256 of the raw request body (of the empty string for a body-less GET)

X-FGAI-Security-Token

Present only for temporary (ASIA…) credentials

The signature is an AWS-SigV4-shaped HMAC over a canonical request:

canonicalRequest =
  METHOD            \n
  canonical_path    \n     # the public request path, e.g. /identity/v1/accounts/{id}/users
  canonical_query   \n     # sorted, percent-encoded query string ("" if none)
  canonical_headers \n     # each SignedHeader, lowercased "name:value", sorted, newline-terminated
  signed_headers    \n     # the SignedHeaders list, ";"-joined
  hex_sha256(body)

The signing key is derived HMAC by HMAC: kDate = HMAC("FGAI4"+secret, date)kRegion = HMAC(kDate, region)kService = HMAC(kRegion, service)kSigning = HMAC(kService, "fgai4_request"), and Signature = hex(HMAC(kSigning, canonicalRequest)). Sign over the public host and path you call (https://api.flexgalaxy.ai) — the gateway preserves them for verification. Requests are rejected outside a ±5-minute clock skew, so keep your clock in sync.

Tip

host, x-fgai-date, and x-fgai-content-sha256 must be in your SignedHeaders. Signing the content hash is what binds the body to the signature.

3. Which capabilities are AK/SK vs. web-only

Everything an integrator needs is on the AK/SK gateway. A few genuinely interactive flows remain browser-only by design.

Capability

On AK/SK gateway?

Path

Accounts — read/manage

/accounts/v1/…

Organizations & OUs — full CRUD, account→OU placement, tree

/organizations/v1/…

Member-account lifecycle — read / rename / suspend / restore / detach a member account

✅ (management credential)

/organizations/v1/{orgId}/accounts/{accountId} — see Manage member accounts

Workforce users — list / invite / disable / enable / remove

⚠️ console/JWT only (not AK/SK)

org IdC directory /identity/v1/organizations/{orgId}/identity-center/users — the earlier account-scoped …/workforce-users AK/SK surface was retired; see Workforce users

IAM / programmatic users — create / list / delete

/identity/v1/accounts/{id}/users

Service users

/identity/v1/accounts/{id}/service-users

Workload identities (federated)

/identity/v1/accounts/{id}/workload-identities/federated

Customer-managed policy authoring (by name)

/identity/v1/accounts/{id}/iam-policies, /permission-sets/{id}/customer-policies

Authorization check (PDP)

/identity/v1/authorize, /identity/v1/authorize/batch

Application registration

one-time (onboarding)

Root / tenant sign-up; interactive password/MFA reset

❌ web-only

https://auth.flexgalaxy.ai

Note

Workforce users (people, onboarded by email, with a role and PENDING/ACTIVE/DISABLED status) are a different surface from IAM/programmatic users (machine identities, created enabled). They are managed in the organization Identity Center directory.

4. Required fields & common pitfalls

These cost integrators real rework — read them before you build.

  • authorize requires principal.ic_session (a boolean) and, for permission-set checks, principal.ps_id. These are required fields. Omitting ic_session authenticates fine but then fails request deserialization and surfaces as a 401, not a 400 — easy to mistake for an auth failure. Always send ic_session (use false for a normal IAM-user check). See [Check authorization (PDP)](https://docs.flexgalaxy.ai/dev/dotid/pdp-authorize/).

  • Batch authorize uses checks, not requests. The body is { "principal": {…}, "context": {…}, "checks": [ { "action": …, "resource": }, ] } and the response is { "results": [ ] } in the same order. All checks share one principal/context.

  • Default-deny. Absence of a matching Allow is DENY (IMPLICIT_DENY); an explicit Deny always wins (EXPLICIT_DENY). Authorization is scoped to your key’s account.

  • A 401 can mean a malformed body, not just a bad signature. Because required-field deserialization runs after authentication, a missing required field is masked as 401. If a request you believe is signed correctly returns 401, check the body shape before the signature.

  • 403 on a workforce/account call means account scope. The {accountId} in the path must be the account your key is bound to. access-key-expired is also a 403.

  • Sign the body hash. X-FGAI-Content-SHA256 must be the SHA-256 of the exact bytes you send; a body that doesn’t match its signed hash is rejected.

5. End-to-end walkthrough

A minimal integrator flow, all with the same signed key:

  1. Provision the tenant tree. Create the account and its organization/OUs (/accounts/v1/…, /organizations/v1/…), placing accounts into OUs.

  2. Author policy. Create an account-scoped customer-managed policy by name and reference it from a permission set (/identity/v1/accounts/{id}/iam-policies, /permission-sets/{id}/customer-policies).

  3. Assign access. Attach the permission set to principals / OUs (assignments cascade read-down where scoped).

  4. Check authorization. Before your app performs an action, ask the PDP (/identity/v1/authorize or /authorize/batch) whether the principal may do it.

  5. Manage employees. Workforce (store-employee) users are the organization Identity Center directory, not an account-scoped surface. This is currently a console/JWT flow (/identity/v1/organizations/{orgId}/identity-center/users) — see Workforce users below. (The earlier account-scoped AK/SK surface /identity/v1/accounts/{id}/workforce-users was retired.)

Each step is one signed HTTPS call to https://api.flexgalaxy.ai. See the worked requests in [External developer API examples](https://docs.flexgalaxy.ai/dev/dotid/examples/external-developer-api/index/).

Manage member accounts

An organization’s management account administers the member accounts under it over AK/SK — no console and no member-account login required. Sign these calls with the management account’s key:

Operation

Call

Read a member account

GET  /organizations/v1/{orgId}/accounts/{accountId}

Rename a member account

PUT  /organizations/v1/{orgId}/accounts/{accountId} — body {"name": …, "description": …}

Suspend a member account

POST /organizations/v1/{orgId}/accounts/{accountId}/suspend

Restore a suspended member account

POST /organizations/v1/{orgId}/accounts/{accountId}/restore

Detach a member account

DELETE /organizations/v1/{orgId}/accounts/{accountId}

Authorization is by management account. Every operation above is allowed only when the account your key is bound to is the management account of {orgId}, and {accountId} is a member of that organization. A key bound to any other account gets a 403.

Suspend is reversible. suspend freezes a member account and signs its users out; restore brings it back to active. Because both are authorized by your management credential — independent of the member account itself — you can always restore a member you suspended; suspend is never a one-way door.

Note

The management account cannot suspend itself (400). To wind down the whole organization, delete the organization rather than suspending its management account.

Scoped delegation (a manager for a company’s accounts)

Sometimes you want one account to administer a whole company’s accounts — e.g. a regional manager who should reach every store under their company, including stores opened later — without granting them anything else. An organization’s management account authors this as an OU → Manager delegation over AK/SK: it delegates a specific permission-set scope from a company OU to a Manager account. From then on the Manager has that scope over every current and future account in that OU’s subtree — and only those. A new store placed in the OU is covered automatically; nothing outside the OU is.

Sign these with the management account’s key:

Operation

Call

Create a delegation

POST   /organizations/v1/{orgId}/delegations — body {"delegatorOuId": …, "delegateeAccountId": …, "scopePermissionSetIds": […]}

List active delegations

GET    /organizations/v1/{orgId}/delegations

Revoke a delegation

DELETE /organizations/v1/{orgId}/delegations/{delegationId}

  • Authorized by the management account. Every call is allowed only when the account your key is bound to is the management account of {orgId}. Any other account gets a 403.

  • Outcomes. A valid delegation returns 201. The OU must belong to {orgId} and each permission set must already be effective at that OU (assigned on the OU or an ancestor) — if it is not, the call is rejected with 422 (you cannot delegate authority the OU does not itself hold). A caller that is not the management account gets 403.

  • Scope only narrows. The Manager can never gain more than the OU holds, and if the Manager re-delegates onward, each hop may narrow the scope but never widen it.

  • Revocation is immediate. DELETE …/delegations/{delegationId} drops the Manager’s inherited access at once — the next authorization check reflects it, with no cached grants.

Tip

This complements the per-account transitive delegation authoring path (/identity/v1/accounts/{accountId}/delegations), which an account uses to delegate its own scope upward. Both are now reachable over AK/SK: the account path is authorized for the account itself or its org’s management account; the OU → Manager path above is management-account only.

Workforce users (Identity Center directory)

The account-scoped /identity/v1/accounts/{id}/workforce-users AK/SK surface was retired and now returns 404. If you built against it, your calls will 404 — do not use it.

Workforce (store-employee) users are canonically the organization’s Identity Center directory:

Was (retired, account-scoped, AK/SK)

Now (canonical, org-scoped)

GET  …/accounts/{id}/workforce-users

GET  /identity/v1/organizations/{orgId}/identity-center/users

POST …/accounts/{id}/workforce-users (invite email+role)

POST /identity/v1/organizations/{orgId}/identity-center/users

POST …/workforce-users/{u}/disable | /enable

POST …/identity-center/users/{u}/disable | /enable

POST …/workforce-users/{u}/rotate-credentials

POST …/identity-center/users/{u}/reset-password

DELETE …/workforce-users/{u}

DELETE …/identity-center/users/{u}

Programmatic access: the org IdC directory is authorized on every operation and accepts STS temporary credentials, so you can manage workforce users headlessly — no console required. The flow:

  1. As the IdC user, obtain temporary ASIA… credentials via the STS session-token flow (available through the console or CLI). The credentials are gateway-agnostic — they work on the public API.

  2. Sign your /identity/v1/organizations/{orgId}/identity-center/users calls with FGAI-HMAC-SHA256 and include the X-FGAI-Security-Token header (temporary-credential requirement — see §2). The public gateway preserves the path, so sign over the path you call (§2).

Each operation is checked against identitycenter:User:{verb} (List/Read/Create/Update/Delete/ Disable/Enable/ResetPassword), so the calling user must hold a covering Identity Center permission set (e.g. IdentityCenterFullAccess) assigned in the organization’s management account; a caller without it gets 403. The Bearer-JWT/console path continues to work unchanged.

Pure AK/SK (no interactive user)? If you have only a service access key and want to manage workforce users headlessly, assume a role that carries the identitycenter:User:* permission and act with its temporary credentials — see Manage workforce (Identity Center) users headlessly (M2M).

IAM roles & AssumeRole

A service credential (or JWT user) can create per-account IAM roles and assume them for temporary, scoped credentials — the AWS-faithful cross-account mechanism:

  • POST /identity/v1/accounts/{accountId}/roles — create a role (trust policy + attached permission policies).

  • POST /identity/v1/sts/assume-role — assume a role by roleFrn; returns temporary ASIA credentials (used with an X-FGAI-Security-Token header) that act in the role’s account with its permissions.

Cross-account administration between accounts in one organization uses the auto-provisioned OrganizationAccountAccessRole in each member account: the management account assumes it to manage that member’s IAM.

The same assume-role mechanism powers headless workforce-user management — see Manage workforce (Identity Center) users headlessly (M2M).