# USM MCP Protocol

Scope: contract-only (no internal infra/storage).

## Base URL
- API Gateway base: `https://api.g3nretailstack.com/usm`
- Health check: USM does not expose a `/stat` endpoint. Use `POST /usm/session/validate` for connectivity checks.
- Sessions: `/usm/session`
- Service accounts: `/usm/service_account`
- API keys: `/usm/api_key`

All responses use the shared envelope `{ success, data?, error?, stats? }` where:
- `success` is boolean.
- `data` holds payloads on success.
- `error` carries `{ major, minor, details? }` tags with `en_US` messages and redaction of secrets.
- `stats` includes request_id/build/latency/bandwidth/metrics and optional actor/session/user passthrough. `build` (`{ build_major, build_minor, build_id }`) is inside `stats`.

Pagination: list endpoints default limit **8**, clamp **1–256**, return opaque cursors (`next_token` and split cursors for active/doomed when `status=all`).

## Auth + tenancy
- Auth placement: USM uses JSON body auth for sessions and API keys; only `POST /usm/api_key/validate` accepts `x-api-key`. See [/common/headers-identity.html](https://doc.g3nretailstack.com/common/headers-identity.html).
- Human sessions: most endpoints require a valid `session_guid` (validated internally by USM).
- Service accounts: `POST /usm/api_key/validate` accepts `x-api-key` (or body `api_key`) and returns principal details (`orgcode`, `org_status`, `roles`) for downstream authorization.
- Owner-only (org-gated): service-account and API-key management endpoints require an **owner** session for the requested org; non-owner members get `403 not-owner`, and non-associated callers get `404 not-found` (anti-enumeration).


## Usage patterns (headless)
- Stack-wide SOPs & operations catalog: <a href="https://doc.g3nretailstack.com/story/operations.html" target="_blank" rel="noopener noreferrer">/story/operations.html</a>.
- Super-usecase scenarios + QA status: <a href="https://doc.g3nretailstack.com/story/super-usecases.html" target="_blank" rel="noopener noreferrer">/story/super-usecases.html</a>.
- This protocol stays contract-only; use the catalogs for workflow expectations.

## Endpoints

### `POST /usm/session/create`
Issues a session for a verified UAS user/email with sliding TTL (default 3600s). Email inputs are canonicalized (trim + lowercase) before UAS lookups. Enforces per-user cap (default 1024; overridden by UAS `max_active_sessions` 32–8192).

Request includes email + passcode, optional caption/label/TTL overrides, and passthrough context (`actor`, `reason`).

Success `200`: payload with `session_guid`, `user_id`, status, expiry, TTL fields, optional caption/label; standard `stats` (includes `build`).

Error tags: `invalid-passcode` (401; also used for unknown emails), `user-not-verified` / `email-not-verified` (403), `too-many-sessions` (429), `session-cap-invalid` (500), plus validation errors.

### `POST /usm/session/validate`
Validates/touches a session. If expired or UAS user/email falls out of verified, the session is doomed with the matching reason.

Request includes `session_guid` and optional context (`actor`, `reason`).

Success `200`: refreshed expiry (if `ttl_refresh_enabled=true`) and current session fields including `last_touched_at` (ISO timestamp of last validate/touch) and `session_fingerprint` (non-reversible SHA-256 hash for correlation).

Errors: `session-not-found` (404), `session-doomed` (410), `ttl-expired` (401), `user-suspended` (401), `user-doomed` (401), `email-unverified` (401), `email-doomed` (401).

### `POST /usm/session/close`
Dooms a session with reason `closed`.

Request includes `session_guid` and optional context.

Success `200`: `{ session_guid, user_id, status: "doomed", doom_reason: "closed", doomed_at_utc }`.

Errors: `session-not-found` (404), `session-doomed` (410).

### `POST /usm/session/get`
Fetches a session by `session_guid`. Optional archived lookup.

Request includes `session_guid`, optional `include_archived`, optional context.

Success `200`: session payload (active or doomed) including `last_touched_at` and `session_fingerprint`. If not in the primary store and `include_archived=true`, returns archived copy.

Errors: `validation-error` for missing session_guid; `session-not-found` (404) when neither active/doomed nor archived.

### `POST /usm/session/list`
Lists sessions for the **caller** (requires an active `session_guid`) by status (active|doomed) with pagination. Optional archived listing for the same user.

Request includes `session_guid`, optional status filter, pagination cursors, label filters (`label_prefix`/`label_contains`) and `caption_contains`, optional archived listing with date bounds, optional context.

Success `200`: sessions, cursors (`next_token`, `next_token_active`, `next_token_doomed`), optional `archived_sessions` + `archive_next_token` when `include_archived=true`.

Errors: `missing-session` (400) if `session_guid` absent; `invalid-status` (400) if not active|doomed|all; plus session validity errors (`session-not-found` 404, `session-doomed` 410, `ttl-expired`/user/email status 401).

### `POST /usm/session/logout_other_devices`
Dooms all other `active` sessions for the user who owns the caller `session_guid` (keeps the caller session active).

Request includes `session_guid` and optional context (`actor`, `reason`).

Success `200`: sets a per-user `logout_other_devices_before_utc` marker and best-effort dooms other active sessions. Sessions created before the marker are rejected on `validate`/`list` with reason `revoked`. Returns counts only (no other users’ session GUIDs).

Errors: same session validity errors as `session/list`/`session/validate` (including `revoked` when the caller session predates the user revoke marker).

### `POST /usm/session/logout_everywhere`
Sets a per-user revoke marker and best-effort dooms `active` sessions (including the caller session).

Request includes `session_guid` and optional context (`actor`, `reason`).

Success `200`: returns the `revoke_before_utc` marker plus best-effort doom counts. Sessions created before the marker are rejected on `validate` and `list` with reason `revoked`.

Errors: same session validity errors as `session/list`/`session/validate`.

## Service accounts (API Gateway)

Service accounts are org-bound non-human identities (e.g., connectors/automation). They carry `roles[]` and own one or more API keys.

### `POST /usm/service_account/create`
Creates a service account (owner session required; org must be `verified`).

### `POST /usm/service_account/list`
Lists service accounts for an org (owner session required).

### `POST /usm/service_account/status`
Sets service account status (currently `doomed` only; terminal). Dooming a service account invalidates its API keys.

## API keys (API Gateway)

API keys are long-lived bearer secrets owned by a service account. The full `api_key` is returned **only once** on create.

### `POST /usm/api_key/create`
Creates an API key for a service account (owner session required; org must be `verified`). Returns `api_key` once, plus `api_key_id` and `api_key_fingerprint`.

### `POST /usm/api_key/list`
Lists API keys for a service account (owner session required). Returns marker fields that may invalidate keys:
- `revoke_before_utc` (service-account marker)
- `org_revoke_before_utc` (org-wide marker)
- `org_api_key_max_age_seconds` (org-level expiry policy; default disabled)

Each listed key may also include derived flags:
- `revoked_by_marker` / `revoked_by_org_marker` when a revoke marker invalidates the key.
- `expired_by_policy` when `org_api_key_max_age_seconds` invalidates the key.

### `POST /usm/api_key/revoke`
Revokes (dooms) a single API key (owner session required).

### `POST /usm/api_key/revoke_all`
Sets a service-account `revoke_before_utc` marker (owner session required). Keys with `created_at < revoke_before_utc` are invalid on `api_key/validate` even if their stored `status` remains `active`.

### `POST /usm/api_key/revoke_all_org`
Sets an org-wide `revoke_before_utc` marker (owner session required). All keys in the org with `created_at < revoke_before_utc` are invalid on `api_key/validate` even if their stored `status` remains `active`.

### `POST /usm/api_key/policy_set`
Sets org-level API-key expiry policy (owner session required; org must be `verified`).

Input: `api_key_max_age_seconds` (integer seconds) or `null` to disable expiry (default).

Enforcement: when enabled, `api_key/validate` rejects keys older than `now - api_key_max_age_seconds` with `401 unauthorized` (`invalid-api-key`, reason `expired`) even if their stored `status` remains `active` (no per-request writes).

### `POST /usm/api_key/validate`
Validates an API key (preferred header `x-api-key`). Success returns principal details:
- `principal_type=service_account`
- `orgcode`, `org_guid`, `org_status`
- `roles[]`
- `api_key_id`, `api_key_fingerprint`, `service_account_guid`

## Rules and limits
- Only verified UAS users with verified email can create sessions (UAS lookup on create).
- Sliding TTL default 3600s; `ttl_seconds` clamped between 1 and 86400; `ttl_refresh_enabled` controls refresh on validate.
- Per-user cap default 1024 active sessions; override via UAS `userConfigSet` to 32–8192.
- Doom reasons: `ttl-expired`, `closed`, `logout-other-devices`, `logout-everywhere`, `revoked`, `user-suspended`, `user-doomed`, `email-unverified`, `email-doomed`, `manual`. `doomed_at_utc` always set.
- Doom retention: kept for a limited window, then archived off the primary store (retrievable via `include_archived=true` or `session/list` with `include_archived` and optional date/label filters).

## Roles
USM does not enforce org-scoped role-based access. Session operations require a valid `session_guid`; API key operations require a valid `api_key`. Service account creation requires `roles` (array of role strings). Authorization is identity-based.

## Example envelopes
Success:
```json
{
  "success": true,
  "data": { "session_guid": "[redacted]", "user_guid": "u-abc", "ttl_seconds": 3600 },
  "stats": { "service": "usm", "call": "sessionCreate", "timestamp_utc": "2026-01-01T00:00:00Z", "build": { "build_major": "MONDAY", "build_minor": "0000000000", "build_id": "MONDAY-0000000000" } }
}
```
Error:
```json
{
  "success": false,
  "error": {
    "error_code": "usm.auth_invalid",
    "http_status": 401,
    "retryable": false,
    "major": { "tag": "invalid-session", "message": { "en_US": "Session invalid" } }
  },
  "stats": { "service": "usm", "call": "sessionValidate", "timestamp_utc": "2026-01-01T00:00:00Z", "build": { "build_major": "MONDAY", "build_minor": "0000000000", "build_id": "MONDAY-0000000000" } }
}
```


## Idempotency & retries
- All read/list calls (e.g., `session/get`, `session/list`, `api_key/list`, `api_key/validate`) are safe to retry with identical inputs (read-only, no side effects).
- `session/create` is **not** idempotent — retrying creates a new session. Verify existence via `session/get` before retrying a failed create.
- `session/close`, `session/logout_other_devices`, and `session/logout_everywhere` are safe to retry (already-doomed sessions return `410`; revoke markers are idempotent).
- `api_key/revoke`, `api_key/revoke_all`, and `api_key/revoke_all_org` are safe to retry (already-revoked keys return appropriate status; revoke markers are idempotent).

## Known pitfalls
- **Pagination cursors**: `next_token` is opaque JSON. Do not modify, decode, or persist cursors across sessions — they may change format between deploys.
- **Anti-enumeration 404**: some org-scoped reads return `404` even when the record exists, if the caller is not associated with the org. Treat `404` as ambiguous; verify caller association before assuming "not found".

> **Note:** USM sessions do not use revision tracking. The `expected_revision` pattern does not apply to session endpoints. The pitfalls about `expected_revision` (missing revision returning `428`, stale revision triggering `409`) are relevant to other services (OFM, PVM, MRS, etc.) but not to USM session or API-key operations.

## OpenAPI
- Contract schema: <a href="https://doc.g3nretailstack.com/usm/openapi.yaml" target="_blank" rel="noopener noreferrer">https://doc.g3nretailstack.com/usm/openapi.yaml</a>


_Build MONDAY-1776194870 • 2026-04-14T19:27:50.000Z • [© 1999 Microhouse Systems Inc. All rights reserved.](https://doc.g3nretailstack.com/common/copyright-license.html)_
