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.
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:
read_customers,write_customersread_orders,write_ordersread_products,write_productsread_marketing_events,write_marketing_eventsread_orders(extended retention) — for predictive LTVread_themes— pixel install verificationread_locales— for translation routingread_inventory,write_inventory
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.
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.