API recipes
Short, complete patterns. Each lists the scopes to grant and the calls to make. Every write is idempotent, so a crashed job can simply run again.
In-store purchases from a POS or cash register
Section titled “In-store purchases from a POS or cash register”Customers who buy in person earn on the same balance as online.
Scopes: customers:read, points:write.
- At checkout, identify the customer:
GET /customers?email=(or keep the Shopify customer id on your loyalty card). - Award points per receipt with the receipt number as
source_ref:
curl -X POST "$CHARM/customers/7712345/points/earn" \ -H "Authorization: Bearer $CHARM_KEY" \ -H "Idempotency-Key: pos-receipt-4471" \ -H "Content-Type: application/json" \ -d '{ "points": 42, "source_ref": "pos-receipt-4471", "reason": "In-store purchase, Prague shop" }'The receipt number doubles as the idempotency key and the ledger reference: a register that sends the same receipt twice never double-awards.
Returns in store: POST /customers/{id}/points/deduct with the same
source_ref prefix (pos-return-4471). The response reports requested and
applied, since a deduction stops at a zero balance.
Loyalty in the helpdesk
Section titled “Loyalty in the helpdesk”Show balance, tier, codes and history next to every ticket, and let agents fix things.
Scopes: customers:read, points:read for the card; add points:write
for goodwill points and redemptions:write if agents may redeem.
- Card:
GET /customers?email={ticket.customer.email}, thenGET /customers/{id}fornext_tier, and/transactions?limit=5for recent history. For Gorgias there is a ready-made card, see Gorgias. - Goodwill points:
POST /customers/{id}/points/adjustwithdeltaand areasonthe shopper will see in their history. - No-code helpdesks that cannot mint a key per click send
Idempotency-Key: auto: an identical click within a minute is refused instead of awarding twice.
Sync a CRM or data warehouse
Section titled “Sync a CRM or data warehouse”Mirror balances and tiers nightly, then stay current with webhooks.
Scopes: customers:read, points:read, webhooks:manage.
- Backfill: page through
GET /customers?limit=250, followingnext_cursorwhilehas_moreis true. Pages are stable under concurrent writes. - Stay current: subscribe to
points.earned,points.adjusted,reward.redeemedandtier.changed. Each event carriescustomer_id(the same GID the API uses) andcustomer_legacy_id; deduplicate on the eventid. - Reconcile weekly with
GET /analytics/summary(members, points issued and redeemed, outstanding liability).
Let an AI assistant run the program
Section titled “Let an AI assistant run the program”Merchants and agencies connect Claude or ChatGPT to Charm over MCP: every endpoint the key allows becomes a tool.
Scopes: start read-only; add writes only for trusted setups.
- Connect as described in MCP for AI assistants. OAuth works in claude.ai and ChatGPT; Claude Code can use a key directly.
- Every tool publishes its output schema, and errors come back with the code, what to fix, the request id and a link here, so assistants correct themselves.
- Writes carry the same idempotency and budget guards as the REST API.
Headless storefronts and apps
Section titled “Headless storefronts and apps”See Headless storefronts: customer session tokens let the browser or app call Charm directly, for one customer, with CORS.