Skip to content

Surfaces

Interactive API Explorer: Explorer

Base: https://api.g3nretailstack.com/pmc (custom domain; stage trimmed). OpenAPI: https://doc.g3nretailstack.com/pmc/openapi.yaml.

Responses use { success, data?, error?, build, stats? }. stats includes non-reversible session_fingerprint/api_key_fingerprint for correlation; session_guid is never returned.

Auth + tenancy

  • Required: x-orgcode header.
  • Auth: x-session-guid (user session) or x-api-key (org-bound service account). For POSTs, you may also pass session_guid or api_key in the JSON body; GETs use headers.
  • Optional cost attribution: x-cccode header (or body cccode). Format ^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$, canonicalized to uppercase; invalid values or header/body mismatch → HTTP 400.
  • Roles: read requires pmc_view (owner implied; accepts pvv/viewer and pma/admin synonyms). Writes require pmc_publish (owner implied; accepts pma/admin synonym).

Identifier policy

  • Direct get/update/status calls require GUID/ID fields (*_id or legacy *_guid where that is the canonical field name). Code-based lookups are resolve/search only.
  • Responses never include both *_id and *_guid for the same record (no dual-field output).
  • Exceptions (email-based UAS, PVM resolve, MRS container+record_id) are listed in /common/ids-codes.html.

Surface Types (explicit)

API Gateway

  • Status: Available.
  • Base: https://api.g3nretailstack.com/pmc
  • Notes: Primary tenant surface for PMC queries and publish workflows.

Direct Lambda

  • Status: Not offered.
  • Notes: No direct Lambda surface is documented for PMC.

CLI

  • Status: Available.
  • Command: g3n pmc ... (API Gateway).
  • Notes: See cli/README.md.

MCP

  • Status: Available.
  • Canonical protocol: https://mcp.g3nretailstack.com/pmc/PROTOCOL.md
  • Mirror: https://doc.g3nretailstack.com/pmc/PROTOCOL.md

Request builder (canonical)

Headers (canonical)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "x-cccode: $CCCODE" # optional
-H "content-type: application/json"

Field placement

  • GET: query string; auth/tenancy in headers.
  • POST: JSON body; auth/tenancy in headers (body auth accepted for convenience).

GET template

bash
curl -sS -G "https://api.g3nretailstack.com/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"

POST template

bash
curl -sS -X POST "https://api.g3nretailstack.com/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"}'

Field placement (GET vs POST)

  • GET: parameters go in the query string; auth/tenancy in headers. Do not send JSON bodies on GET.
  • POST: parameters go in the JSON body; auth/tenancy in headers (body auth is accepted for convenience, but headers are canonical).

Retry guidance (endpoint class)

  • GET reads/lists/search are safe to retry with identical inputs.
  • POST writes (publish runs, profile/pointer updates, pack lifecycle) should only be retried when you can tolerate duplicates or the endpoint uses expected_revision for safe replay (refetch on 409).

Anti-enumeration (404)

Some org-scoped reads return 404 not-found when the caller is not associated with the org. This hides org existence from unrelated callers. Treat 404 as ambiguous (not found or not associated) and use the self-check flow in /common/troubleshooting.html.

Pagination: default limit=8, clamp 1–256, opaque JSON next_token cursors (echo verbatim).

Optimistic concurrency: revisioned records require expected_revision when updating existing state. Missing → HTTP 428 expected-revision-required; mismatch → HTTP 409 conflict with current record snapshot + current revision.

Core model + invariants

  • Product identity: variant_id × channel_guid (sales channel implies logical facility + market/locale).
  • Each publish creates an immutable revision with a required reason.
  • Exactly one revision may be online at a time for a given product (or none). online_state=offline means no online pointer.
  • PMC is query-authoritative: list/search return PMC snapshots (no PVM resolver call during queries).
  • Auto-offline: when upstream PVM containers become ineligible, PMC clears the online revision (minutes drift window).

Build

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
  • GET /build/stats — build metadata for the running service.
    • Headers: x-orgcode and x-session-guid or x-api-key

Example:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/build/stats" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID"

Product (serving)

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"

GET /product/get

Fetch by product_id, or by variant_id + channel_guid. Query:

  • product_id OR (variant_id + channel_guid) Headers: x-orgcode and x-session-guid or x-api-key Returns { product, online_revision } where:
  • product (head) includes identity (product_id/product_key/variant_id/style_id/brand/category/department/division), channel + locale (channel_guid, channel_code, market_code, logical_guid, locale_codes, default_locale_code), match keys (variant_code, sku, identifier_keys, alias_keys, barcode_values), and stamp metadata (pack_refs, taxonomy_version, biz_unit_code, region_code, country_code, online_rev, online_rev_id, online_reason_code, offline_reason_code, max_rev, last_publish_*, timestamps, revision).
  • online_revision is the current online revision (if any).

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/product/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "product_id=PROD123"

curl -sS -G "https://api.g3nretailstack.com/pmc/product/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "variant_id=VAR123" \
  --data-urlencode "channel_guid=CHN123"

GET /product/list

Query: one filter at a time, plus optional online_state, limit, next_token. Headers: x-orgcode and x-session-guid or x-api-key Exact-match filters only; one filter at a time (multiple filters → HTTP 400 invalid-input).

  • Filters (one of):
    • ID facets: variant_id, style_id, brand_id, vendor_id, manufacturer_id, category_id, department_id, division_id, channel_guid, logical_guid
    • Code/locale facets: style_code, category_code, department_code, division_code, channel_code, market_code, locale_code, default_locale_code
    • Match keys: variant_code, sku, identifier_type + identifier_value, alias_tag + alias_value, barcode_value
  • online_state=online|offline|both (default both); legacy only_online=true maps to online.
  • No filter → org-wide list (bucketed; no scans).
  • Canonicalization: codes uppercased; identifier_type lowercased; alias_value whitespace-collapsed then uppercased; locale codes trimmed; barcode requires digits-only (length 8/12/13/14).
  • identifier_type and identifier_value must be provided together; same for alias_tag + alias_value.

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/product/list" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "style_id=STYLE123" \
  --data-urlencode "online_state=online" \
  --data-urlencode "limit=8"

curl -sS -G "https://api.g3nretailstack.com/pmc/product/list" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "sku=SKU-001" \
  --data-urlencode "online_state=both"

POST /product/group

Bounded group-by counts for a single dimension. Provide dimension and optional values[]; omit values to return top buckets (bounded by limit, default 50). When values[] is provided, PMC serves counts from the rollup table when available; otherwise it falls back to search-plane aggregations. Top buckets always use the search plane. For category/department/division group-by (IDs or codes), require channel_guid, channel_code, or logical_guid to bound the query.

  • online_state=online|offline|both (default both).
  • dimension allowlist: variant_id, style_id, brand_id, vendor_id, manufacturer_id, category_id, department_id, division_id, channel_guid, logical_guid, style_code, category_code, department_code, division_code, channel_code, market_code, locale_code, default_locale_code, biz_unit_code, region_code, country_code.

Examples:

sh
curl -sS -X POST "https://api.g3nretailstack.com/pmc/product/group" \
  -H "content-type: application/json" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  -d '{
    "dimension": "category_id",
    "values": ["CAT123"],
    "online_state": "online",
    "channel_guid": "CHN123"
  }'

Partial-match search (prefix/contains/regex) for operational workflows. Results are PMC product heads.

  • Required: q.
  • Optional: field=any|sku|code|barcode|identifier|alias, mode=prefix|contains|regex (default contains), online_state, channel_guid, logical_guid.
  • Guardrails:
    • contains requires q length ≥ 3; prefix ≥ 2.
    • field=barcode requires digits-only q length ≥ 4.
    • regex requires pmc_publish (or owner) and is applied to normalized lowercase text. Headers: x-orgcode and x-session-guid or x-api-key

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/product/search" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "q=SHOE" \
  --data-urlencode "field=code" \
  --data-urlencode "mode=prefix"

curl -sS -G "https://api.g3nretailstack.com/pmc/product/search" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "q=012345678905" \
  --data-urlencode "field=barcode" \
  --data-urlencode "mode=contains"

GET /product/revision/list

List revision history for a product (paged). Filters: product_id or variant_id + channel_guid, optional online_state. Headers: x-orgcode and x-session-guid or x-api-key

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/product/revision/list" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "product_id=PROD123" \
  --data-urlencode "online_state=both" \
  --data-urlencode "limit=8"

Online pointer control

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"
  • POST /product/online/set — set which revision is online. Requires expected_revision, plus rev + rev_id. Optional reason_code. Identify the product by product_id or variant_id + channel_guid.
  • POST /product/online/clear — clear the online pointer (no revision online). Requires expected_revision. Optional reason_code.

Pointer kinds (staged/preview/fallback)

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"
  • GET /product/pointer/getpointer_kind required; returns pointer or null.
    • Query: pointer_kind, plus product_id or (variant_id + channel_guid)
    • Headers: x-orgcode and x-session-guid or x-api-key
  • Example:
sh
curl -sS -G "https://api.g3nretailstack.com/pmc/product/pointer/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "pointer_kind=staged" \
  --data-urlencode "product_id=PROD123"
  • POST /product/pointer/setpointer_kind, rev, rev_id required; optional reason, effective_at, expires_at (ISO-8601). Use expected_revision when updating an existing pointer.
  • POST /product/pointer/clearpointer_kind + expected_revision.

Content packs

Packs are immutable, versioned bundles referenced by pack_refs in publish runs.

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"
  • POST /pack/create — create a pack.
    • Inline JSON: content_type=application/json with payload provided; service computes MD5. Max size 25 MB.
    • Presigned upload: provide size_bytes + content_md5 (hex). Returns presign.upload_url + upload_token; pack status pending_upload.
    • pack_kind is required and must match [a-z0-9_-]{2,32}; pack_id optional (if provided, pack_version is required; otherwise pack_version defaults to 1).
  • POST /pack/complete — finalize presigned upload. Requires pack_id, pack_version, upload_token, expected_revision. Validates size, marks pack active.
  • GET /pack/get — fetch a pack by pack_id + pack_version.
    • Query: pack_id, pack_version
    • Headers: x-orgcode and x-session-guid or x-api-key
  • GET /pack/list — list versions for a pack_id (paged).
    • Query: pack_id, optional limit, next_token
    • Headers: x-orgcode and x-session-guid or x-api-key

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/pack/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "pack_id=PACK123" \
  --data-urlencode "pack_version=1"

curl -sS -G "https://api.g3nretailstack.com/pmc/pack/list" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "pack_id=PACK123" \
  --data-urlencode "limit=8"

Publishability profiles

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"
  • GET /publish-profile/get — fetch profile by channel_code.
    • Query: channel_code
    • Headers: x-orgcode and x-session-guid or x-api-key
  • POST /publish-profile/set — create/update profile. Update requires expected_revision.
    • Fields: required_sku (bool), required_identifier_types[], required_alias_tags[].

Example:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/publish-profile/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "channel_code=WEB"

Publish runs (client-driven)

Publish orchestration is client-driven; calling start does not publish by itself.

Canonical curl headers (API Gateway)

bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"
  • POST /publish/run/start — start a run.
    • Required: reason.
    • confirm_all=true is required to publish all variants (no selector).
    • Primary selector (choose one): variant_id (requires style_id), style_id, brand_id, vendor_id, manufacturer_id, category_id.
    • Optional secondary filters: control_type, service_flag, kit_flag.
    • Optional channel scope: logical_guid, channel_guid, channel_code, market_code (run will fail if no active channels match).
    • Optional stamps: taxonomy_version, biz_unit_code, region_code, country_code (each must match [A-Z0-9_-]{2,64}).
    • Optional pack_refs (max 8); each ref must point to an active pack, and pack_kind (if provided) must match.
  • POST /publish/run/step — process the next page. Requires run_id + expected_revision; optional limit (default 8). Updates counts (variants_processed, publish_ok, publish_skipped, skipped_reasons) and appends manifest parts.
  • GET /publish/run/get — fetch run status and counters.
    • Query: run_id
    • Headers: x-orgcode and x-session-guid or x-api-key
  • POST /publish/run/cancel — cancel a running run (expected_revision required).

Manifests

  • GET /publish/run/manifest/list — list manifest parts (part number, hash, size, schema version).
    • Query: run_id, optional limit, next_token
    • Headers: x-orgcode and x-session-guid or x-api-key
  • GET /publish/run/manifest/presign — presign a manifest part download.
    • Query: run_id, part_number
    • Headers: x-orgcode and x-session-guid or x-api-key
  • Manifest content is NDJSON (gzip). Some HTTP clients auto-decompress; accept either.

Examples:

sh
curl -sS -G "https://api.g3nretailstack.com/pmc/publish/run/get" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "run_id=RUN123"

curl -sS -G "https://api.g3nretailstack.com/pmc/publish/run/manifest/list" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "run_id=RUN123" \
  --data-urlencode "limit=8"

curl -sS -G "https://api.g3nretailstack.com/pmc/publish/run/manifest/presign" \
  -H "x-orgcode: $ORGCODE" \
  -H "x-session-guid: $SESSION_GUID" \
  --data-urlencode "run_id=RUN123" \
  --data-urlencode "part_number=1"

Error tags (representative)

invalid-input, forbidden-role, unauthorized, not-found, conflict, expected-revision-required, invalid-state, upstream-failed, internal-error.

CLI (API Gateway)

PMC CLI commands mirror core API surfaces and require --orgcode + --session-guid. Base defaults to https://api.g3nretailstack.com/pmc.

Examples:

  • g3n pmc product-get --product-id <id> --orgcode ORG --session-guid ...
  • g3n pmc product-list --style-id <id> --online-state online --limit 8 --orgcode ORG --session-guid ...
  • g3n pmc product-list-by-identifier --type sku --value SKU123 --orgcode ORG --session-guid ...
  • g3n pmc product-search --q ABC --mode contains --orgcode ORG --session-guid ...
  • g3n pmc product-revision-list --product-id <id> --orgcode ORG --session-guid ...
  • g3n pmc product-online-set --product-id <id> --expected-revision <rev> --rev 2 --rev-id <rev_id> --reason-code SYSTEM.MANUAL_ROLLBACK --orgcode ORG --session-guid ...
  • g3n pmc publish-profile-set --channel-code SHOPIFY --required-sku true --required-identifier-types '["sku"]' --orgcode ORG --session-guid ...
  • g3n pmc publish-run-start --reason "weekly" --channel-code SHOPIFY --orgcode ORG --session-guid ...
  • g3n pmc publish-run-step --run-id <id> --expected-revision <rev> --orgcode ORG --session-guid ...

Service-account API keys can call the API directly via x-api-key headers; the CLI currently uses sessions.

Error envelope example (canonical)

json
{
  "success": false,
  "error": {
    "error_code": "pmc.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": "pmc", "timestamp_utc": "2026-01-21T00:00:00Z", "request_id": "req-123" }
}

Role requirements (by endpoint family)

  • Read/list/search: pmc_view (aliases: pvv) or owner.
  • Publish runs + online pointer: pmc_publish (alias: pma) or owner.

Idempotency & retries

  • Publish run start is not idempotent; reuse run id if you retry after timeout.
  • Run step and pointer updates require expected_revision; re-read on 409/428 before retrying.

Common pitfalls

  • Missing channel_code or logical_guid in queries yields empty results.
  • online_state defaults to both; set explicitly for online/offline views.

Examples (core families)

Publish run start

json
{ "reason": "weekly publish", "channel_code": "WEB", "style_id": "STYLE_ID" }

Response (shape):

json
{ "success": true, "data": { "run_id": "RUN_ID", "revision": "RUN_REV" }, "build": { "...": "..." }, "stats": { "...": "..." } }

Product get

json
{ "product_id": "PRODUCT_ID" }

Response (shape):

json
{ "success": true, "data": { "product": { "product_id": "PRODUCT_ID" } }, "build": { "...": "..." }, "stats": { "...": "..." } }