Appearance
Surfaces
Interactive API Explorer: Explorer
The authoritative surface is the OpenAPI spec:
/crm/openapi.yaml
Additional surfaces are available: MCP (/crm/mcp.html) and CLI (g3n crm ...; see cli/README.md).
Surface Types (explicit)
API Gateway
- Status: Available.
- Base:
https://api.g3nretailstack.com/crm - Notes: Primary tenant surface for CRM and loyalty workflows.
Direct Lambda
- Status: Not offered.
- Notes: No direct Lambda surface is documented for CRM.
CLI
- Status: Available.
- Command:
g3n crm ...(API Gateway). - Notes: See
cli/README.md.
MCP
- Status: Available.
- Canonical protocol:
https://mcp.g3nretailstack.com/crm/PROTOCOL.md - Mirror:
https://doc.g3nretailstack.com/crm/PROTOCOL.md
Auth + tenancy
- Required headers:
x-orgcodeandx-session-guid(user session) orx-api-key(org-bound service account). - Header auth is canonical; body auth is accepted where documented. See /common/headers-identity.html.
- Optional cost attribution:
x-cccode(or request fieldcccode) where supported; see OpenAPI. - Non-associated callers receive
404 not-found(anti-enumeration). - Facility context:
x-logical-guid(required for operational actions; see OpenAPI per-path).x-channel-code(required where documented; see OpenAPI per-path).
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 (API Gateway)
Headers (canonical)
bash
-H "x-orgcode: $ORGCODE"
-H "x-session-guid: $SESSION_GUID" # or: -H "x-api-key: $API_KEY"
-H "content-type: application/json"Template
bash
curl -sS -X POST "https://api.g3nretailstack.com/crm/<endpoint>" \
-H "content-type: application/json" \
-H "x-orgcode: $ORGCODE" \
-H "x-session-guid: $SESSION_GUID" \
-d '{"...": "..."}'Notes
- Replace
<endpoint>with a route from the OpenAPI inventory. - Header auth is canonical; body
session_guid/api_keyis accepted where documented.
Customer surfaces
POST /crm/customer/create|get|list|searchPOST /crm/customer/dedupe/listPOST /crm/customer/merge|merge/listPOST /crm/customer/consent/set|getPOST /crm/customer/fraud/assess|fraud/listPOST /crm/customer/hold/list|hold/resolvePOST /crm/customer/flag/set|flag/list
B2B account surfaces
POST /crm/account/create|get|list|status/set|updatePOST /crm/account/contact/create|get|list|status/set|update
Tax exemption certificate surfaces
POST /crm/exemption/certificate/create|get|listPOST /crm/exemption/certificate/status/set
Comments and inbox surfaces
POST /crm/comment|comment/get|comment/list|comment/revise|comment/status|comment/reportPOST /crm/inbox/create|get|list|status|state
Endpoint inventory (OpenAPI parity)
Request/response schema names reference OpenAPI component schemas.
| Method | Path | Request schema | Response schema |
|---|---|---|---|
| POST | /account/contact/create | AccountContactCreateRequest | AccountContactEnvelope |
| POST | /account/contact/get | AccountContactGetRequest | AccountContactEnvelope |
| POST | /account/contact/list | AccountContactListRequest | AccountContactListEnvelope |
| POST | /account/contact/status/set | AccountContactStatusSetRequest | AccountContactEnvelope |
| POST | /account/contact/update | AccountContactUpdateRequest | AccountContactEnvelope |
| POST | /account/create | AccountCreateRequest | AccountEnvelope |
| POST | /account/get | AccountGetRequest | AccountEnvelope |
| POST | /account/list | AccountListRequest | AccountListEnvelope |
| POST | /account/status/set | AccountStatusSetRequest | AccountEnvelope |
| POST | /account/update | AccountUpdateRequest | AccountEnvelope |
| POST | /comment | CommentAddRequest | CommentEnvelope |
| POST | /comment/get | CommentGetRequest | CommentEnvelope |
| POST | /comment/list | CommentListRequest | CommentListEnvelope |
| POST | /comment/report | CommentReportRequest | CommentReportEnvelope |
| POST | /comment/revise | CommentReviseRequest | CommentEnvelope |
| POST | /comment/status | CommentStatusRequest | CommentEnvelope |
| POST | /customer/consent/get | CustomerConsentGetRequest | CustomerConsentEnvelope |
| POST | /customer/consent/set | CustomerConsentSetRequest | CustomerConsentEnvelope |
| POST | /customer/create | CustomerCreateRequest | CustomerEnvelope |
| POST | /customer/dedupe/list | CustomerDedupeRequest | CustomerDedupeEnvelope |
| POST | /customer/flag/list | CustomerFlagListRequest | CustomerFlagListEnvelope |
| POST | /customer/flag/set | CustomerFlagSetRequest | CustomerFlagEnvelope |
| POST | /customer/fraud/assess | CustomerFraudAssessRequest | CustomerFraudAssessEnvelope |
| POST | /customer/fraud/list | CustomerFraudListRequest | CustomerFraudListEnvelope |
| POST | /customer/get | CustomerGetRequest | CustomerEnvelope |
| POST | /customer/hold/list | CustomerHoldListRequest | CustomerHoldListEnvelope |
| POST | /customer/hold/resolve | CustomerHoldResolveRequest | CustomerHoldEnvelope |
| POST | /customer/list | CustomerListRequest | CustomerListEnvelope |
| POST | /customer/merge | CustomerMergeRequest | CustomerEnvelope |
| POST | /customer/merge/list | CustomerMergeListRequest | CustomerMergeListEnvelope |
| POST | /customer/search | CustomerSearchRequest | CustomerListEnvelope |
| POST | /exemption/certificate/create | ExemptionCertificateCreateRequest | ExemptionCertificateEnvelope |
| POST | /exemption/certificate/get | ExemptionCertificateGetRequest | ExemptionCertificateEnvelope |
| POST | /exemption/certificate/list | ExemptionCertificateListRequest | ExemptionCertificateListEnvelope |
| POST | /exemption/certificate/status/set | ExemptionCertificateStatusSetRequest | ExemptionCertificateEnvelope |
| POST | /giftcard/issue | StoredValueIssueRequest | StoredValueEnvelope |
| POST | /giftcard/redeem | StoredValueRedeemRequest | StoredValueEnvelope |
| POST | /inbox/create | InboxCreateRequest | InboxEnvelope |
| POST | /inbox/get | InboxGetRequest | InboxEnvelope |
| POST | /inbox/list | InboxListRequest | InboxListEnvelope |
| POST | /inbox/state | InboxStateRequest | InboxEnvelope |
| POST | /inbox/status | InboxStatusRequest | InboxEnvelope |
| POST | /loyalty/adjust | LoyaltyAdjustRequest | LoyaltyTxnEnvelope |
| POST | /loyalty/earn | LoyaltyEarnRequest | LoyaltyTxnEnvelope |
| POST | /loyalty/expire | LoyaltyExpireRequest | LoyaltyExpireEnvelope |
| POST | /loyalty/policy/get | LoyaltyPolicyGetRequest | LoyaltyPolicyEnvelope |
| POST | /loyalty/policy/set | LoyaltyPolicySetRequest | LoyaltyPolicyEnvelope |
| POST | /loyalty/redeem | LoyaltyRedeemRequest | LoyaltyTxnEnvelope |
| POST | /loyalty/restore | LoyaltyRestoreRequest | LoyaltyTxnEnvelope |
| POST | /loyalty/reverse | LoyaltyReverseRequest | LoyaltyTxnEnvelope |
Error tags
Common tags (see /common/error-tags.html for definitions): validation-error, unauthorized, forbidden, not-found, expected-revision-required, conflict, invalid-state, throttled, internal-error.
Example envelopes
Success envelope (shape-only):
json
{
"success": true,
"data": { "example": "see schema for fields" },
"build": { "build_major": "MONDAY", "build_minor": "0000000000", "build_id": "MONDAY-0000000000" },
"stats": { "call": "example", "service": "crm", "timestamp_utc": "2026-01-21T00:00:00Z" }
}Error envelope (shape-only):
json
{
"success": false,
"error": {
"error_code": "crm.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": "crm", "timestamp_utc": "2026-01-21T00:00:00Z", "request_id": "req-123" }
}Role requirements (by endpoint family)
- Read/list/search:
crm_view(or owner). - Customer updates:
crm_manage/crm_edit(or owner). - Privacy/consent:
crm_privacy_admin(or owner). - Loyalty:
loyalty_admin(or owner). - Stored value:
giftcard_admin(or owner).
Idempotency & retries
- Use
expected_revisionfor updates to revisioned customer records. - Loyalty earn/redeem are not idempotent unless documented.
Common pitfalls
- Consent flags gate exports and some reads.
- Anti-enumeration returns 404 for non-associated callers.
Examples (core families)
Customer create
json
{ "customer": { "email": "cust@example.com", "caption": "Jane Doe" }, "reason": "signup" }Response (shape):
json
{ "success": true, "data": { "customer_id": "CUSTOMER_ID" }, "build": { "...": "..." }, "stats": { "...": "..." } }Loyalty earn
json
{ "customer_id": "CUSTOMER_ID", "points": 100, "reason": "purchase" }Response (shape):
json
{ "success": true, "data": { "loyalty_txn_id": "LOYALTY_ID" }, "build": { "...": "..." }, "stats": { "...": "..." } }