switching clears the token & responses
No token
34

Onboard an operator and manage roles

List existing operators, create one (setup token out-of-band), grant a time-bounded role with step-up, confirm, review grants, and later revoke. Requires iam-platform-admin throughout — so the VERY FIRST operator cannot be created here: it is seeded once, out of band (scenario 52).

  1. GET /v1/admin/operators → review existing operators before creating another
  2. POST /v1/admin/operators → 201 (operator created; setup/MFA-enrolment token out-of-band)
  3. PUT /v1/admin/operators/{operatorId}/roles/{role} → grant a time-bounded role (step-up)
  4. GET /v1/admin/operators/{operatorId} → confirm the operator and their active roles
  5. GET /v1/admin/operators/{operatorId}/roles → review active role grants
  6. DELETE /v1/admin/operators/{operatorId}/roles/{role} → revoke a role (step-up)
GET/v1/admin/operatorsadminList operators

Review existing operators (cursor-paginated) before creating another — avoids duplicating an account.

Query parameters
ℹ︎Field guide — what each value means & where it comes from2 fields

Lists operator accounts (cursor-paginated). No request body. Requires platform-admin auth (Authorization / x-gateway-context handled by the tester+gateway); caller must hold the iam-platform-admin role. Only two optional query params.

limitqueryintegeroptionalyou choose
The user chooses how many operators to return per page. Integer 1-100, defaults to 20 if omitted. Out-of-range values cause a 400 VALIDATION_ERROR.
cursorquerystringoptionalfrom a response
Opaque pagination cursor of 1-512 chars. Do not type it freely; copy it from the prior response's meta.nextCursor field to fetch the next page. Omit on the first request.
Bearer token
GET https://api.kerja.team/v1/admin/operators?limit=20
↩︎Response guide — what comes back & what each value means10 fields

200 OK. Body is the standard { data, meta } envelope: data is an array of OperatorListItem objects, meta carries the page count and cursor-pagination token. No special response headers (no Set-Cookie, no Cache-Control: no-store).

dataarrayalways
Array of operator account summaries (OperatorListItem) for this page. Empty array when no operators match.
data[].idUUIDalways
Operator account identifier. Feed into GET/PATCH /v1/admin/operators/{operatorId} for detail or updates.
data[].emailstringalways
Operator's email address (login identifier).
data[].displayNamestringalways
Human-readable name shown in operator lists/UI.
data[].statusenumalways
Lifecycle status of the operator account.
  • activeAccount is enabled and may authenticate.
data[].createdAtISO-8601always
Timestamp when the operator account was created.
data[].activeRoleCountintegeralways
Number of roles currently assigned/active for this operator.
metaobjectalways
Pagination metadata for the returned page.
meta.countintegeralways
Number of items returned in data for this page.
meta.nextCursorstringalways
Opaque cursor for the next page; pass back as ?cursor to fetch more. Null when there are no further pages.
POST/v1/admin/operatorsadminCreate operator (admin)

Needs Idempotency-Key: <uuid>. Always returns meta.mfaEnrollmentRequired = true; the setup/account token is delivered out-of-band. The operator brings the account online via scenario 33. Same-key retry replays the original 201.

Request body (JSON)
ℹ︎Field guide — what each value means & where it comes from3 fields

Creates an operator account (requires iam-platform-admin via gateway context, handled by the tester). Idempotent: you must set a fresh Idempotency-Key UUID header yourself. A setup/MFA-enrolment token is generated and delivered out-of-band; it is never returned.

Idempotency-KeyheaderUUIDrequiredclient-generated
You generate a fresh UUID per create request and set it yourself. Makes the call replay-safe; reusing the same key with a different body returns 409, and a bad/missing key returns 400.
emailbodystringrequiredyou choose
You type the new operator's email address. Must be a valid email, max 320 chars. Identifies the account and is where the out-of-band setup token is delivered.
displayNamebodystringoptionalyou choose
Optional human-readable name you type for the operator, 1-200 chars.
Bearer token
POST https://api.kerja.team/v1/admin/operators
↩︎Response guide — what comes back & what each value means6 fields

Success is 201 Created returning the standard { data } envelope (no special response headers). data is the newly created operator record; meta carries the MFA-enrolment flag. The MFA-enrolment / account-setup token is delivered out-of-band and is never present in the body.

data.idUUIDalways
Server-assigned operator account id. Feed into follow-up calls such as GET /v1/admin/operators/{operatorId} or role-assignment endpoints.
data.emailstringalways
The operator's email address, echoed back from the request (valid email, up to 320 chars).
data.displayNamestringconditional
Human-readable display name (1-200 chars). Present when displayName was supplied in the request; the field is optional on input.
data.statusenumalways
Lifecycle state of the freshly created operator account.
  • activeThe account is created in the active state and ready for use (MFA enrolment still pending per meta.mfaEnrollmentRequired).
data.createdAtISO-8601always
UTC timestamp when the operator account was created.
meta.mfaEnrollmentRequiredbooleanalways
Signals that the operator must still complete MFA enrolment / account setup using the out-of-band token.
  • trueMFA enrolment is required before the operator can fully authenticate; an out-of-band setup token was generated and delivered.
PUT/v1/admin/operators/{operatorId}/roles/{role}adminGrant / extend a role (step-up)

Step-up required. expiresInDays is 1–365 (default 90). The unqualified platform_admin is never grantable via this API — it always returns 422 IAM-ROLE-02 (break-glass / out-of-band seed only). You cannot grant a role to yourself (422 IAM-ROLE-03).

⛓ Needs an out-of-band value?
Path parameters
Request body (JSON)
ℹ︎Field guide — what each value means & where it comes from6 fields

Grants or extends a time-bounded operator role (upsert). Requires the iam-platform-admin operator role plus a step-up factor in the body (stepUp.password or stepUp.recoveryCode); the tester/gateway supply Authorization / x-gateway-context. No Idempotency-Key required.

operatorIdpathUUIDrequiredfrom a response
The operator receiving the grant. You do not type a fresh value; copy operatorId from a prior operator list/get response in the tester. Malformed UUID returns 400; unknown operator returns 404. Note: granting to yourself returns 422 (IAM-ROLE-03).
rolepathenumrequiredyou choose
The role to grant/extend. You choose one of the six operator roles or the unqualified platform_admin. Any other value returns 400.
  • iam-platform-adminAdminister operator accounts & role grants and set the global sign-up policy.
  • tenant-lifecycle-operatorProvision and manage tenant lifecycle.
  • support-acting-in-tenantMint tenant-scoped act-as tokens.
  • security-investigatorCross-tenant forensic audit read.
  • support-read-onlyRead-only support; grantable but backs no endpoint in this surface today (no-op access).
  • billing-adminBilling administration; grantable but backs no endpoint in this surface today (no-op access).
  • platform_adminAccepted by the router but ALWAYS rejected by the service with 422 (IAM-ROLE-02) regardless of any other field — the unqualified platform_admin is never grantable via this API (break-glass / out-of-band seed only).
stepUpbodyobjectrequiredyou choose
Step-up re-authentication factor, verified before the mutation. Must contain at least one of password or recoveryCode. A failed factor returns 401.
stepUp.passwordbodystringconditionalyou choose
The operator's current account password (1-1024 chars). You type it. Required unless you instead supply stepUp.recoveryCode; at least one of the two must be present.
stepUp.recoveryCodebodystringconditionalauthenticator
A one-time recovery code from the operator's MFA authenticator setup (1-128 chars). Obtained from your saved recovery codes, not typed freely. Required unless you instead supply stepUp.password; at least one of the two must be present.
expiresInDaysbodyintegeroptionalyou choose
How many days the grant stays valid (integer 1-365). You choose it; defaults to 90 if omitted. Out-of-range values return 400.
Bearer token
PUT https://api.kerja.team/v1/admin/operators/2a1c0000-0000-7000-8000-000000000001/roles/security-investigator
↩︎Response guide — what comes back & what each value means5 fields

200 OK with a JSON { data } envelope wrapping a GrantResult object (no special response headers; no Set-Cookie or Cache-Control noted). The grant is an upsert: an existing active grant of this role has its expiry extended, otherwise a new grant is inserted; either way the response shape is identical.

dataobjectalways
The GrantResult envelope payload describing the granted (or extended) operator role grant.
data.operatorIdUUIDalways
UUID of the operator who received the grant; echoes the {operatorId} path param. Use to confirm the grant landed on the intended operator.
data.roleenumalways
The role that was granted; echoes the {role} path param.
  • iam-platform-adminAdminister operator accounts & role grants; set the global sign-up policy.
  • tenant-lifecycle-operatorProvision and manage tenant lifecycle.
  • support-acting-in-tenantMint tenant-scoped act-as tokens.
  • security-investigatorCross-tenant forensic audit read.
  • support-read-onlyRead-only support role (grantable but backs no endpoint in this surface today).
  • billing-adminBilling administration role (grantable but backs no endpoint in this surface today).
data.expiresAtISO-8601always
Timestamp when this time-bounded grant expires (now + expiresInDays, default 90 days). Use to display/track when the operator will lose the role.
data.grantedByUUIDalways
UUID of the platform admin operator who performed the grant (the step-up-verified caller). Use for audit display.
GET/v1/admin/operators/{operatorId}adminGet one operator + roles

Confirms the operator and their active role grants (OperatorDetail).

Path parameters
ℹ︎Field guide — what each value means & where it comes from1 field

No request body. Read-only fetch of one operator and their active roles; requires a platform-admin gateway context (Authorization / x-gateway-context handled by the tester + gateway). The only caller input is the operatorId in the path.

operatorIdpathUUIDrequiredfrom a response
The operator to fetch. Do not type a value freely; copy an operator's id from a prior listing/get response (e.g. the GET /v1/admin/operators list, where each item's `id` field is this UUID). Must be a valid UUID or the call returns 400 VALIDATION_ERROR; an unknown id returns 404 NOT_FOUND.
Bearer token
GET https://api.kerja.team/v1/admin/operators/2a1c0000-0000-7000-8000-000000000001
↩︎Response guide — what comes back & what each value means9 fields

200 OK returning the standard { data } envelope with a single OperatorDetail object (no special response headers; not paginated). The data object carries the operator's identity, status, creation time, and an array of their active role grants.

dataobjectalways
The OperatorDetail object describing the requested platform operator.
data.idUUIDalways
Operator's unique identifier; feed back into operator role grant/revoke calls.
data.emailstringalways
Operator's login email address.
data.displayNamestringalways
Human-readable name shown in the operator list/detail UI.
data.statusenumalways
Lifecycle status of the operator account.
  • activeOperator account is enabled and may authenticate and hold roles.
data.createdAtISO-8601always
Timestamp the operator account was created.
data.rolesarrayalways
Active role grants currently held by the operator; empty array if none.
data.roles[].roleenumalways
Name of the granted operator/platform role.
  • iam-platform-adminFull platform administration over operators, tenants, and roles.
  • security-investigatorRead/investigation access to security and audit data.
data.roles[].expiresAtISO-8601always
Expiry timestamp of this time-bounded role grant; after this the grant is no longer active.
GET/v1/admin/operators/{operatorId}/rolesadminList an operator's role grants

Active role grants with each grant's expiry window.

Path parameters
ℹ︎Field guide — what each value means & where it comes from1 field

No request body and no query params. Authenticated via gateway context (handled by the tester); caller must hold iam-platform-admin. Supply only the operatorId path param.

operatorIdpathUUIDrequiredfrom a response
The operator whose active role grants you want to list. You do not type this freely; copy it from a prior API response in the tester (e.g. an operator list or get response). A malformed (non-UUID) value returns 400, and an unknown operator returns 404.
Bearer token
GET https://api.kerja.team/v1/admin/operators/2a1c0000-0000-7000-8000-000000000001/roles
↩︎Response guide — what comes back & what each value means8 fields

200 OK with the standard { data, meta } envelope; data is an array of the operator's active RoleGrant items, returned as a single page (meta.nextCursor is always null here). No special response headers (no Set-Cookie/Cache-Control noted).

data[]arrayalways
Array of the operator's active role grants. May be empty if the operator has no active grants; each item is a RoleGrant object with grant metadata.
data[].roleenumalways
The granted operator role name. Combine with operatorId/role to drive the PUT/DELETE grant endpoints.
  • iam-platform-adminAdminister operator accounts & role grants; set the global sign-up policy (§3.50-3.55, §3.65-3.66).
  • tenant-lifecycle-operatorProvision and manage tenant lifecycle (§3.56-3.60).
  • support-acting-in-tenantMint tenant-scoped act-as tokens (§3.61-3.63).
  • security-investigatorCross-tenant forensic audit read (§3.64).
  • support-read-onlyRead-only support role; grantable but backs no endpoint in this surface (reserved).
  • billing-adminBilling administration role; grantable but backs no endpoint in this surface (reserved).
data[].expiresAtISO-8601always
Timestamp at which this time-bounded grant expires. Client uses it to show remaining validity and decide whether to extend via the PUT grant endpoint.
data[].grantedByUUIDalways
Operator ID of the principal who granted this role (truncated in the example). Identifies who authorized the grant for audit display.
data[].createdAtISO-8601always
Timestamp when the grant was created/inserted. Useful for ordering and showing grant age.
metaobjectalways
Pagination metadata envelope for the listing.
meta.countintegeralways
Number of role-grant items returned in data for this page.
meta.nextCursorstringalways
Opaque keyset cursor for the next page, or null. Always null for this endpoint since results are returned as a single page.
  • nullNo further pages; this endpoint always returns a single page so the value is always null.
DELETE/v1/admin/operators/{operatorId}/roles/{role}adminRevoke a role (step-up)

Step-up required. Revoking a role the operator doesn't actively hold is NOT a no-op — it rolls back with no audit row and returns 404 NOT_FOUND. Revoking your own last iam-platform-admin grant returns 422 (IAM-ROLE-LAST-ADMIN).

⛓ Needs an out-of-band value?
Path parameters
Request body (JSON)
ℹ︎Field guide — what each value means & where it comes from5 fields

Revokes one operator role grant. Requires an operator session (x-gateway-context, handled by the tester/gateway) with the iam-platform-admin role, plus step-up re-auth: the body must carry a stepUp object with at least one factor (current password or a recovery code). No Idempotency-Key is required.

operatorIdpathUUIDrequiredfrom a response
The operator whose role grant is being revoked. You obtain this UUID from a prior list/get response (e.g. the operators listing), not by typing it freely. Malformed (non-UUID) values return 400; an unknown operator returns 404.
rolepathenumrequiredyou choose
Which operator role to revoke from this operator. You pick one of the six grantable operator roles. The unqualified platform_admin is NOT accepted here (-> 400). If the operator has no active grant of that role, the call returns 404.
  • iam-platform-adminRevokes administration rights over operator accounts, role grants, and the global sign-up policy. Blocked with 422 (IAM-ROLE-LAST-ADMIN) if it would remove your own last iam-platform-admin grant.
  • tenant-lifecycle-operatorRevokes the ability to provision and manage tenant lifecycle.
  • support-acting-in-tenantRevokes the ability to mint tenant-scoped act-as tokens.
  • security-investigatorRevokes cross-tenant forensic audit read access.
  • support-read-onlyRevokes the read-only support role (grantable but currently backs no endpoint in this surface).
  • billing-adminRevokes the billing administration role (grantable but currently backs no endpoint in this surface).
stepUpbodyobjectrequiredyou choose
Step-up re-authentication container. Required on every call; must contain at least one of password or recoveryCode. A failed step-up factor returns 401.
stepUp.passwordbodystringconditionalyou choose
The operator's current account password (1-1024 chars), typed by the user. Provide this OR stepUp.recoveryCode; at least one of the two must be present.
stepUp.recoveryCodebodystringconditionalauthenticator
A one-time recovery code (1-128 chars) from the operator's MFA recovery codes, used as the step-up factor instead of the password. Provide this OR stepUp.password; at least one of the two must be present.
Bearer token
DELETE https://api.kerja.team/v1/admin/operators/2a1c0000-0000-7000-8000-000000000001/roles/security-investigator
↩︎Response guide — what comes back & what each value means4 fields

200 OK with the standard { data } envelope wrapping a RevokeResult object; no notable response headers (no Set-Cookie, no Cache-Control: no-store). A no-op revoke (no active grant) does not reach this success shape — it rolls back and returns 404.

dataobjectalways
The RevokeResult object describing the role grant that was revoked.
data.operatorIdUUIDalways
ID of the operator whose role was revoked; echoes the {operatorId} path param. Use to confirm the correct operator was targeted.
data.roleenumalways
The operator role that was revoked; echoes the {role} path param. One of the six operator roles (never platform_admin, which cannot be targeted here).
  • security-investigatorThe security-investigator operator role grant was revoked (example value shown in the doc).
  • <operator role>Any one of the six operator roles defined in Appendix A — Operator Roles, excluding platform_admin which is rejected with 400.
data.revokedbooleanalways
Confirms the grant was revoked. Always true on a 200 success; a no-op (nothing active to revoke) instead returns 404 rather than revoked:false.
  • trueThe active role grant was found and revoked, and an operator_role_revoked audit row was written.