Authentication & scopes
Three auth surfaces
Each surface has a distinct auth model — appropriate to its threat surface and use case.
| Surface | Auth method | Granularity |
|---|---|---|
Admin API (/api/v1/...) | Bearer token (copt_...) | Per-token scopes |
Public endpoints (/api/public/...) | None (CORS allow-list) or API key (pk_...) | Per-shop |
| Webhooks (inbound) | HMAC SHA-256 signature | Per-source secret |
| Webhooks (outbound) | HMAC SHA-256 signature you sign | Per-endpoint secret |
Admin API — bearer tokens
Token format
copt_live_aB3xY9zKqMnPwR2vT4uH7jL5sQ8eFc1g
copt_prefix identifies as Sumeru Systems API tokenlive_(ortest_) environment marker- 32-character random body (base62)
Tokens are stored as SHA-256 hashes; the raw token is shown once at creation and never displayed again.
Creating tokens
Admin UI: Settings → API tokens → Create. Pick scopes (see catalog below). Token shown once.
Programmatic creation (for managing many shops): use the
/api/v1/api-keys endpoint with a master token (Enterprise).
Sending the token
GET /api/v1/customers/cus_abc123 HTTP/1.1
Host: api.sumeru.systems
Authorization: Bearer copt_live_aB3xY9zKqMnPwR2vT4uH7jL5sQ8eFc1g
Authorization header is required on every admin API call.
Token security
- Tokens are stored hashed (SHA-256); raw never persisted
- All token comparisons use
crypto.timingSafeEqual - Tokens can be rotated anytime (old token revoked immediately)
- Tokens are scope-gated; minimum-privilege principle
- Admin UI shows last-used timestamp + IP per token
Scopes catalog
| Scope | What it grants |
|---|---|
customers:read | Read Customer 360 profiles |
customers:write | Update profiles, tag, enroll in journeys |
orders:read | Read order history |
orders:write | Create / cancel / refund orders |
attribution:read | Read attribution data |
campaigns:read | Read campaigns |
campaigns:write | Create / launch / pause campaigns |
journeys:read | Read journeys + enrollments |
journeys:write | Create / edit / pause journeys |
products:read | Read product catalog |
products:write | Update products, prices, inventory |
analytics:read | Read dashboards + DIE recommendations |
webhooks:read | List webhook subscriptions |
webhooks:write | Create / update webhook subscriptions |
audit:read | Read audit log |
* | All scopes (admin only — discouraged) |
Tokens declare their scopes at creation; the API enforces on
every call. Calling an endpoint outside scope returns 403
with code scope_required.
Public endpoints — CORS or API key
Public endpoints are storefront-facing (called from your shop's JavaScript). They use:
CORS allow-list (default)
Each shop has a configured allow-list of domains
(yourshop.com, www.yourshop.com). Requests from those
origins succeed without an API key.
fetch('https://api.sumeru.systems/api/public/reviews', {
headers: { 'X-Shop-Domain': 'yourshop.com' }
})
API key (for headless / custom platforms)
For storefronts not on standard Shopify domains (Hydrogen, custom Next.js, etc.):
pk_live_xY7aB3cKz9...
Sent as X-Public-Key header. Public keys are scoped to
public endpoints only — cannot access admin API.
Webhooks — HMAC signatures
Inbound (Sumeru receiving)
When Shopify / WhatsApp / marketplace fires a webhook to Sumeru, the body is HMAC-signed by the source. We verify:
- Shopify: HMAC-SHA256 with shop secret,
X-Shopify-Hmac-Sha256header - WhatsApp (Meta): HMAC-SHA256 with app secret,
X-Hub-Signature-256header - Marketplaces: per-marketplace contract (per webhooks)
Signature mismatches reject with 401.
Some messaging providers (MSG91, Gupshup) do not HMAC-sign their delivery callbacks. For those, authentication is a shared secret token on the callback URL, and the handler fails closed (403) on a missing/incorrect token. See Messaging-provider webhooks.
Outbound (Sumeru notifying you)
When Sumeru sends events to your endpoint (Zapier, custom integration), we HMAC-sign the body. You verify:
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Header: X-Sumeru-Signature: sha256=<hex>
Your endpoint secret is shown once at webhook subscription creation. Rotate via the admin or API.
Shopify scopes (the underlying)
Sumeru as a Shopify app declares these scopes; you'll see them at install. The set was pruned in 2026-05 to match actual usage:
| Scope | Powers |
|---|---|
read_customers, write_customers | Customer 360, journeys, loyalty enrolment |
read_orders, read_all_orders | Order history + extended retention for predictive LTV |
read_products, write_products | Catalog operations, product pipeline |
read_inventory, write_inventory | Inventory forecast + write-inventory |
read_locations | Location-scoped inventory writes |
write_discounts, read_discounts | Loyalty redemption + campaign discount codes |
read_own_subscription_contracts | Subscription MRR / churn / dunning in the Revenue Hub |
write_pixels, read_customer_events | Web Pixel + UTM attribution capture |
read_markets | Markets & currency routing |
write_marketing_events | Campaign + marketing-event reporting |
read_content, write_content | Blog engine + content publishing |
read_files, write_files | Generated images + media |
read_translations, write_translations | Translations engine |
write_legal_policies | Policy/compliance content |
These are Shopify-side scopes the merchant approves at install. The Sumeru admin token scopes (above) gate Sumeru API access on top of whatever Shopify-side access the app has.
read_own_subscription_contracts is a protected scope — the subscription
economics in the Revenue Hub
stay hidden until it's approved for the app. Adding subscription scopes also
triggers a Shopify re-review.
Token rotation
POST /api/v1/api-keys/<id>/rotate HTTP/1.1
Authorization: Bearer copt_live_...
Returns the new token in the response. The old token is revoked immediately. Plan for ~5 seconds of overlap if your client is mid-flight when rotation fires.
Brute-force / rate-limit protection
- Failed auth attempts rate-limited at 10/min per IP
- 100 failed attempts in 24h: IP blocked for 1h
- 1000 failed attempts in 24h: alert to admin
Successful auth resets counters per IP.