Appearance
Minimum Viable Flow (Login -> Org -> Product -> Publish)
This walkthrough is a copy-paste minimal flow that exercises the core services end-to-end: login -> org setup (OFM) -> product creation (PVM) -> channel publish (PMC).
All POST requests use JSON bodies; all GET requests use query parameters. Auth is carried in headers for org-scoped services, with body-auth exceptions for USM and UTL. Replace placeholders as needed.
Operator-only note: invitations and org verification are IAM direct Lambda steps (not API Gateway). You cannot complete this flow end-to-end without operator access for those steps. See User Provisioning for the complete operator setup flow (user creation, email verification, invitation minting).
Downloadable collections (Postman + Insomnia)
Import a collection and run the same flow in order:
- Postman: /common/collections/g3nretailstack-minimum-viable-flow.postman_collection.json
- Insomnia: /common/collections/g3nretailstack-minimum-viable-flow.insomnia_collection.json SDK snippet set (Node.js + Python):
- /common/sdk-snippets.html Client shim (header/body normalization + retries):
- /common/client-shim.html SDK integration checklist:
- /common/sdk-integration-checklist.html
Notes:
- The org verification step is operator-only (direct Lambda / IAM); the collection includes a placeholder item with instructions.
- Both collections use variables like
API_BASE,SESSION_GUID,ORGCODE, andORG_GUID. You can edit them manually; the Postman collection also includes tests to populate variables from responses.
0) Set placeholders
sh
export API_BASE="https://api.g3nretailstack.com"
export EMAIL="user@example.com"
export PASSCODE="Passw0rd!123"
export ORGCODE="ACME"
export INVITE_CODE="INV123"1) Login (USM session)
Auth Placement
USM uses body auth — session_guid and credentials live in the JSON body, not headers. All downstream org-scoped services (OFM, PVM, PMC, etc.) use header auth (x-session-guid). UTL also uses body auth. See /common/headers-identity.html.
sh
curl -sS -X POST "$API_BASE/usm/session/create" \
-H 'Content-Type: application/json' \
-d '{"email":"'$EMAIL'","passcode":"'$PASSCODE'","caption":"cli","session_label":"cli"}'Capture:
session_guid->SESSION_GUIDuser_id->USER_GUID
2) Create org (OFM)
sh
curl -sS -X POST "$API_BASE/ofm/org/create" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"orgcode":"'$ORGCODE'","invitation_code":"'$INVITE_CODE'","user_guid":"'$USER_GUID'","caption":"Acme HQ"}'Capture:
org_guidrevision(org record revision)cost_centre.cc_guid(optional but useful later)
3) Verify org (operator-only)
Intentional Operator Gate
Org verification is an intentional security gate. New orgs are created in unverified status and cannot perform org-scoped writes until an operator verifies them via direct Lambda (IAM). This prevents unauthorized tenants from writing data. If you skip this step, all downstream writes (PVM, PMC, ICS, etc.) return 403 org-write-blocked.
Direct Lambda payload for ofm_orgstatusset:
json
{ "org_guid": "ORG_GUID", "status": "verified", "expected_revision": "ORG_REV", "reason": "onboarding" }To invoke in a sandbox environment:
sh
aws lambda invoke \
--function-name ofm_orgstatusset \
--cli-binary-format raw-in-base64-out \
--payload '{"org_guid":"ORG_GUID","status":"verified","expected_revision":"ORG_REV","reason":"onboarding"}' \
--profile g3nretailstack \
/dev/stdoutFor the full ofm_orgstatusset payload shape, see OFM Surfaces.
4) Create facilities (OFM)
You need a logical facility to create a sales channel.
4a) Physical facility
sh
curl -sS -X POST "$API_BASE/ofm/facility/physical/create" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"org_guid":"ORG_GUID","code":"PHYS1","caption":"HQ","address":{"street":"1 Main St","city":"Austin","region":"TX","country":"US"},"phone":"+1-555-0100"}'Capture physical_guid.
4b) Legal facility
sh
curl -sS -X POST "$API_BASE/ofm/facility/legal/create" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"org_guid":"ORG_GUID","code":"LEG1","caption":"Acme LLC","address":{"street":"1 Main St","city":"Austin","region":"TX","country":"US"}}'Capture legal_guid.
4c) Logical facility
sh
curl -sS -X POST "$API_BASE/ofm/facility/logical/create" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"org_guid":"ORG_GUID","code":"LOG1","caption":"Online DC","physical_guid":"PHYS_GUID","legal_guid":"LEG_GUID"}'Capture logical_guid.
5) Create a sales channel (OFM)
sh
curl -sS -X POST "$API_BASE/ofm/sales-channel/create" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"org_guid":"ORG_GUID","logical_guid":"LOGICAL_GUID","channel_code":"WEB","market_code":"US","locale_codes":["en-US"],"default_locale_code":"en-US"}'Capture:
channel_guidrevision(sales channel revision)
Activate the channel (owner-only):
sh
curl -sS -X POST "$API_BASE/ofm/sales-channel/status" \
-H 'Content-Type: application/json' \
-H "x-session-guid: $SESSION_GUID" \
-d '{"org_guid":"ORG_GUID","channel_guid":"CHANNEL_GUID","status":"active","expected_revision":"CHANNEL_REV","reason":"go-live"}'6) Create taxonomy + suppliers (PVM)
PVM POSTs should use the x-session-guid header (canonical); body session_guid is accepted for compatibility. orgcode is required (header shown below).
6a) Division / department / category
sh
curl -sS -X POST "$API_BASE/pvm/division" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"code":"DIV1","caption":"Division 1"}'Capture division_id and revision, then activate:
sh
curl -sS -X POST "$API_BASE/pvm/division/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"division_id":"DIVISION_ID","status":"active","expected_revision":"DIVISION_REV"}'Department:
sh
curl -sS -X POST "$API_BASE/pvm/department" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"division_id":"DIVISION_ID","code":"DEPT1","caption":"Department 1"}'Activate:
sh
curl -sS -X POST "$API_BASE/pvm/department/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"department_id":"DEPARTMENT_ID","status":"active","expected_revision":"DEPARTMENT_REV"}'Category:
sh
curl -sS -X POST "$API_BASE/pvm/category" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"department_id":"DEPARTMENT_ID","code":"CAT1","caption":"Category 1"}'Activate:
sh
curl -sS -X POST "$API_BASE/pvm/category/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"category_id":"CATEGORY_ID","status":"active","expected_revision":"CATEGORY_REV"}'6b) Vendor + manufacturer
sh
curl -sS -X POST "$API_BASE/pvm/vendor" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"code":"VEND1","caption":"Vendor 1"}'Verify vendor:
sh
curl -sS -X POST "$API_BASE/pvm/vendor/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"vendor_id":"VENDOR_ID","status":"verified","expected_revision":"VENDOR_REV"}'Manufacturer mirrors vendor (/pvm/manufacturer + /pvm/manufacturer/status).
sh
curl -sS -X POST "$API_BASE/pvm/manufacturer" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"code":"MFG1","caption":"Manufacturer 1"}'
curl -sS -X POST "$API_BASE/pvm/manufacturer/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"manufacturer_id":"MANUFACTURER_ID","status":"verified","expected_revision":"MANUFACTURER_REV"}'7) Create style + variant (PVM)
7a) Style
sh
curl -sS -X POST "$API_BASE/pvm/style" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"code":"STYLE1","category_id":"CATEGORY_ID","vendor_ids":["VENDOR_ID"],"manufacturer_ids":["MANUFACTURER_ID"],"vendor_primary":"VENDOR_ID","manufacturer_primary":"MANUFACTURER_ID"}'Activate:
sh
curl -sS -X POST "$API_BASE/pvm/style/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","status":"active","expected_revision":"STYLE_REV"}'7b) Variant (with empty selections if OGM has no groups)
sh
curl -sS -X POST "$API_BASE/pvm/variant" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","selections":[],"code":"VAR1"}'Activate:
sh
curl -sS -X POST "$API_BASE/pvm/variant/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","variant_id":"VARIANT_ID","status":"active","expected_revision":"VARIANT_REV"}'7c) Add a SKU identifier (recommended)
sh
curl -sS -X POST "$API_BASE/pvm/identifier/add" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","variant_id":"VARIANT_ID","type":"sku","value":"SKU-001"}'8) Publish (PMC)
PMC requires x-orgcode and x-session-guid headers.
8a) Start a publish run
sh
curl -sS -X POST "$API_BASE/pmc/publish/run/start" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","variant_id":"VARIANT_ID","channel_guid":"CHANNEL_GUID","reason":"initial publish"}'Capture run_id and revision (RUN_REV).
8b) Step the run until completed
sh
curl -sS -X POST "$API_BASE/pmc/publish/run/step" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"run_id":"RUN_ID","expected_revision":"RUN_REV"}'If the response status is still running, repeat the step call using the latest revision from the response.
8c) Fetch the published product
sh
curl -sS -G "$API_BASE/pmc/product/get" \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
--data-urlencode "variant_id=VARIANT_ID" \
--data-urlencode "channel_guid=CHANNEL_GUID"Expected revision + 409 conflict handling
Whenever you update an existing record, include expected_revision from your most recent read.
If a write returns 409 conflict:
- Re-read the record (GET or the relevant
.../getendpoint). - Use the current
revisionfrom the response. - Retry the write with
expected_revisionset to that value.
Example (style status):
sh
# 1) Read current style
curl -sS -G "$API_BASE/pvm/style/get" \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
--data-urlencode "style_id=STYLE_ID"
# 2) Retry with latest revision
curl -sS -X POST "$API_BASE/pvm/style/status" \
-H 'Content-Type: application/json' \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"style_id":"STYLE_ID","status":"active","expected_revision":"LATEST_REV"}'If a write returns 428 expected-revision-required, you attempted to update an existing record without providing expected_revision.