Skip to content

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.

  1. At checkout, identify the customer: GET /customers?email= (or keep the Shopify customer id on your loyalty card).
  2. Award points per receipt with the receipt number as source_ref:
Terminal window
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.

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}, then GET /customers/{id} for next_tier, and /transactions?limit=5 for recent history. For Gorgias there is a ready-made card, see Gorgias.
  • Goodwill points: POST /customers/{id}/points/adjust with delta and a reason the 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.

Mirror balances and tiers nightly, then stay current with webhooks.

Scopes: customers:read, points:read, webhooks:manage.

  1. Backfill: page through GET /customers?limit=250, following next_cursor while has_more is true. Pages are stable under concurrent writes.
  2. Stay current: subscribe to points.earned, points.adjusted, reward.redeemed and tier.changed. Each event carries customer_id (the same GID the API uses) and customer_legacy_id; deduplicate on the event id.
  3. Reconcile weekly with GET /analytics/summary (members, points issued and redeemed, outstanding liability).

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.

See Headless storefronts: customer session tokens let the browser or app call Charm directly, for one customer, with CORS.