Skip to content

Authentication

The CDP API has two credential classes, used for two different purposes.

Data reads (profiles, events, sessions, segments) authenticate with a per-brand API key sent as a Bearer token:

Authorization: Bearer vyg_…
  • A key is the string vyg_ followed by an opaque secret. It is returned exactly once at issuance (or rotation) and is stored only as a SHA-256 hash — it is never logged and never written to the audit trail. Listing keys returns only the key_prefix and metadata.
  • A key is scoped to exactly one brand’s shop. The scope is resolved server-side from your brand_id → connected shop mapping; you never pass a scope, and you can never widen it.
  • A missing or invalid credential returns 401. An authenticated key whose brand has no connected Shopify-shaped integration (so no shop scope can be bound) returns 403.

Issuing, rotating, revoking, and listing keys (/cdp/keys*) require a session credential (a logged-in session token), not an API key. This is enforced: a request to a key-management route that presents a vyg_ API key is rejected with 403:

{
"error": "forbidden",
"error_description": "Key management requires a session credential; an API key cannot manage keys."
}

This is a containment guarantee — a leaked or about-to-be-revoked key cannot be used to mint itself a fresh key or rotate/revoke around its own revocation.

  • Staff may issue / rotate / revoke / list for any brand_id (the target brand is read from the request).
  • A non-staff brand-admin may operate only on their own brand. Naming a different brand_id returns 403.

Even an authorized caller can only mint a key for a brand that resolves to a connected Shopify shop — no scope means no key (403).

CredentialUsed forScope
vyg_ API key (Bearer)data readsexactly one brand’s shop
Session credentialkey managementstaff: any brand · brand-admin: own brand

See Tenant Isolation & Scope for how scope is enforced on every read.