Appearance
Surfaces
Interactive API Explorer: Explorer
Runtime: Node.js 24. Covers payloads, responses, errors, and best-practice usage. Context passthrough (orgcode, cccode) is never required; direct Lambda actions forward them verbatim when present. Email inputs are canonicalized (trim + lowercase). The public /uas/stat API validates/canonicalizes cccode (body or x-cccode header; mismatch → 400). Bearer session_guid values are treated as secrets and are not emitted in response stats or tenant events/audits.
Surface Types (explicit)
API Gateway
- Status: Available (public
/uas/statonly). - Base:
https://api.g3nretailstack.com/uas - Notes:
/uas/statis the only public API Gateway route; all other UAS actions are direct Lambda.
Direct Lambda
- Status: Available (default for non-public UAS actions).
- Notes: See Direct Lambda actions below;
uas_statis also invokable directly for trusted callers.
CLI
- Status: Available.
- Command:
g3n uas ...(direct Lambda). - Notes: Requires
--profile/AWS credentials.
MCP
- Status: Available.
- Canonical protocol:
https://mcp.g3nretailstack.com/uas/PROTOCOL.md - Mirror:
https://doc.g3nretailstack.com/uas/PROTOCOL.md
Auth + tenancy
- API Gateway
/uas/statusesemail+passcodein the JSON body; no org/session headers are required. - Optional cost attribution:
cccodein body orx-cccodeheader (validated/canonicalized). - Direct Lambda actions are IAM-gated for trusted callers and forward
orgcode/cccodewhen present.
Identifier policy
- Direct get/update/status calls require GUID/ID fields (
*_idor legacy*_guidwhere that is the canonical field name). Code-based lookups are resolve/search only. - Responses never include both
*_idand*_guidfor the same record (no dual-field output). - Exceptions (email-based UAS, PVM resolve, MRS
container+record_id) are listed in /common/ids-codes.html.
Request builder (public /uas/stat)
Method: POST only.
Headers (canonical)
bash
-H "content-type: application/json"
-H "x-cccode: $CCCODE" # optionalBody (JSON)
json
{ "email": "user@example.com", "passcode": "Abcd!234", "include_payment_history": false, "actor": "ops-user", "cccode": "ABCD-1234-EFGH" }Template
bash
curl -sS -X POST "https://api.g3nretailstack.com/uas/stat" \
-H "content-type: application/json" \
-H "x-cccode: $CCCODE" \
-d '{"email":"user@example.com","passcode":"Abcd!234","include_payment_history":false,"actor":"ops-user"}'Public API (API Gateway)
POST https://api.g3nretailstack.com/uas/stat
Canonical curl headers
bash
-H "content-type: application/json"
-H "x-cccode: $CCCODE" # optional- Use when you need a snapshot of a user (including emails/payment methods) from a public surface.
- Request
json
{ "email": "user@example.com", "passcode": "Abcd!234", "include_payment_history": false, "actor": "ops-user" }- Response
json
{
"success": true,
"data": { "user_id": "u123", "emails": [...], "payment_methods": [...] },
"build": { "...": "..." },
"revision": "rev-123",
"stats": { "call": "stat", "service": "uas", "timestamp_utc": "2025-12-14T12:00:00Z" }
}- Errors:
validation-error(missing credentials),unauthorized(invalid credentials; does not disclose whether the email exists),internal-error(unexpected). - Best practice: pass
actorfor audit, use the custom domain, and omitinclude_payment_historyunless you need historical payment status. Optionalcccodeis validated/canonicalized (body orx-cccodeheader).
Optimistic concurrency (revision)
For any state-changing operation on an existing user record, you must pass expected_revision matching the current record revision.
- Get the current
revisionfromstat(public) oruserGet/userSnapshot(direct). - On success, update your local
expected_revisionto the responserevision. - Missing
expected_revision→428 expected-revision-requiredwitherror.details.{current_revision,current_record} - Mismatch →
409 conflictwitherror.details.{provided_revision,current_revision,current_record}
Direct Lambda actions (invoke payload JSON)
Direct invoke is the default for all non-public UAS actions (CLI/SDK). uas_stat is also invokable directly for trusted callers and supports user_id-based snapshots.
Users & status
- userCreate:
{ email, passcode, caption?, reason?, actor? }→{ user_id, account_ref }. Errors:duplicate-email,validation-error. - userSnapshot / userGet:
{ user_id, include_payment_history?, actor? }→ snapshot. Errors:not-found,validation-error. - userStatusSet:
{ user_id, status, expected_revision, reason?, actor? }(FSM: unverified→verified/doom, verified↔suspended, suspended→doom). Note: the FSM also has an implicitverified → unverifiedtransition triggered as a side-effect ofemailSetPrimarywhen the new primary email is unverified; this emits auserStatusAutoUnverifyevent. Errors:invalid-transition,not-found. - userConfigSet:
{ user_id, max_active_sessions: number|null, expected_revision, reason?, actor? }(32–8192 when set) →{ user_id, max_active_sessions? }. Errors:validation-error. - Use cases: onboard a user, fetch a snapshot for billing/ops, gate access by status, tune per-user session caps for USM.
Emails (unverified ↔ verified → doomed)
- emailAdd / emailList: add/list emails (paginated).
emailAddrequiresexpected_revision. Rejects duplicates across users.emailListsupportslimit/next_token. - emailIssueToken → emailConfirmToken: verification flow. Both require
expected_revision. Last token wins; tokens expire (48h). Confirm marks email verified. Errors:invalid-token,token-expired,duplicate-email,validation-error. - emailSetPrimary: enforce single primary; primary cannot be doomed. Requires
expected_revision. Side-effect: whenemailSetPrimarychanges the primary to an unverified email and the user status isverified, the user status is automatically downgraded tounverified. This side-effect emits auserStatusAutoUnverifyevent. Errors:invalid-transition,not-found. - emailDoom: terminal. Requires
expected_revision. Errors:invalid-transition,not-found. - Example (list):
json
{ "user_id": "u123", "limit": 8, "next_token": null, "actor": "ops-user" }Response: { "success": true, "data": { "emails": [...], "next_token": null }, "build": {...}, "stats": {...} }
Passcodes
- passcodeSet / passcodeReset:
{ user_id, passcode, expected_revision, reason?, actor? }→{ ok: true }. Enforces policy (length ≥8 with upper/lower/number/special) and reuse guard. Errors:passcode-policy-failed,passcode-reuse,validation-error,not-found. - Use cases: initial set after email verification, rotation, resets after compromise.
Payment methods (pending → active | suspended | doomed; active ↔ suspended; active → doomed; doomed is terminal)
- pmCreate / pmList: add/list payment methods;
pmCreaterequiresexpected_revision. List paginated withlimit/next_token. Uniqueness onprocessor+token_type+token. Default ordering: active → pending → suspended → doomed. - pmSetStatus / pmPromote / pmDemote / pmDoom: require
expected_revision. Manage lifecycle; doomed removes token and is terminal. Errors:payment-uniqueness-conflict,invalid-transition,not-found. - pmVacateToken: requires
expected_revision. Nulls stored token for a doomed/retired PM. Errors:not-found,invalid-transition. - Example (list with pagination):
json
{ "user_id": "u123", "limit": 5, "next_token": "eyJHU0kxUEsiOiJVU0VSIy4uLiJ9" }Response: { "success": true, "data": { "payment_methods": [...], "next_token": "..." }, "build": {...}, "stats": {...} }
Pagination
limitdefault 8, clamped 1–256.next_tokenis opaque (base64 JSON); echo exactly.- Returned when more pages remain. Lists never return partial items within a page.
CLI (direct Lambda invokes)
Script: cli/bin/g3n.js (requires --profile, optional --region; --base-url override for API surfaces such as stat).
Examples:
g3n uas stat --user-id u123 --profile g3nretailstackg3n uas user-create --email a@b.com --passcode 'Abcd!234' --caption 'Staff' --profile g3nretailstackg3n uas email-issue-token --user-id u123 --email a@b.com --expected-revision rev-123 --actor ops --profile g3nretailstackg3n uas pm-list --user-id u123 --limit 5 --profile g3nretailstack- Pagination (CLI cursor):
g3n uas pm-list --user-id u123 --limit 2 --profile g3nretailstack→ copy base64next_token, theng3n uas pm-list --user-id u123 --next-token "$NEXT_TOKEN" --profile g3nretailstack g3n uas user-config-set --user-id u123 --max-active-sessions 2048 --expected-revision rev-123 --profile g3nretailstack
Best practices: always pass --profile, reuse --actor/--reason for audit clarity, and copy next_token verbatim between paged calls.
Error envelope example (canonical)
json
{
"success": false,
"error": {
"error_code": "uas.conflict_revision",
"http_status": 409,
"retryable": false,
"request_id": "req-123",
"trace_id": "trace-abc",
"major": { "tag": "conflict", "message": { "en_US": "Expected revision does not match the current record." } },
"details": { "expected_revision": "3", "current_revision": "4" },
"conflict_snapshot": { "revision": 4 }
},
"build": { "...": "..." },
"stats": { "call": "example", "service": "uas", "timestamp_utc": "2026-01-21T00:00:00Z", "request_id": "req-123" }
}The error block includes the following optional fields (matching the ICS/PPM/SCM canonical pattern):
error_code(string, optional) — machine-readable error code (e.g.uas.conflict_revision).http_status(number, optional) — HTTP status code.retryable(boolean, optional) — whether the caller should retry.request_id(string, optional) — correlation request ID.trace_id(string, optional) — distributed tracing ID.
These fields are present when available; callers should not depend on their presence.
Role requirements (by endpoint family)
- Public stat: no roles; credentialed by email+passcode.
- Direct Lambda (operator/trusted):
uas_operatoror operator IAM (internal onboarding admin tool). - Owner/member roles do not apply to UAS (identity service).
Idempotency & retries
- Use
expected_revisionfor any update to a revisioned user record. userCreateis not idempotent; verify by email before retrying.emailIssueTokenreplaces the prior token; retries are safe with the sameexpected_revision.
Common pitfalls
/uas/statdoes not acceptuser_idfor public callers.- Email is canonicalized (trim + lowercase); duplicates are case-insensitive.
expected_revisionis required for status/email/passcode/payment updates.
Examples (core families)
User create (direct Lambda)
json
{ "email": "user@example.com", "passcode": "Abcd!234", "caption": "Retail staff", "actor": "ops-user" }Response (shape):
json
{ "success": true, "data": { "user_id": "u123" }, "build": { "...": "..." }, "stats": { "...": "..." } }Email verification (direct Lambda)
json
{ "user_id": "u123", "email": "user@example.com", "expected_revision": "rev-123", "actor": "ops-user" }Response (shape):
json
{ "success": true, "data": { "token": "base64token" }, "build": { "...": "..." }, "stats": { "...": "..." } }