API Key Security
Supp has two key types: publishable keys (pk_live_) for client-side widget embeds, and secret keys (sk_live_) for server-side API access.
Use publishable keys for widget embeds
Publishable keys (pk_live_) are designed for the data-key attribute in your widget embed. They can only access widget endpoints and are protected by domain restrictions and spend caps. A stolen publishable key cannot read conversations, manage billing, or access any dashboard API.
Never expose secret keys in client-side code
Secret keys (sk_live_) have full API access and must only be used server-side. Store them in environment variables and never commit them to version control.
Where to declare your key
Widget HTML embed (client-side)
Use a publishable key (pk_live_) via the data-key attribute. Always set domain restrictions on this key.
<script
src="https://supp.support/widget.js"
data-key="pk_live_your_publishable_key"
async
></script>REST API Request body (server-side)
Pass in the JSON body when calling the widget endpoint from your backend. This is the most secure method because the key never reaches the browser.
// Server-side only (Node.js, Python, etc.)
const response = await fetch("https://api.supp.support/api/widget", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
api_key: process.env.SUPP_API_KEY, // from environment variable
message: userMessage,
}),
});MCP / API Authorization header (server-side)
When using the MCP server or calling API endpoints programmatically, pass the key as a Bearer token or X-API-Key header.
# Bearer token (recommended, MCP spec standard)
curl -X GET https://api.supp.support/api/conversations \
-H "Authorization: Bearer sk_live_your_key_here"
# X-API-Key header (also supported)
curl -X GET https://api.supp.support/api/conversations \
-H "X-API-Key: sk_live_your_key_here"Environment .env file (recommended)
Store your key in an environment variable. Never commit it to version control.
# .env (add to .gitignore)
SUPP_API_KEY=sk_live_your_key_here
# Access in your code
# Node.js: process.env.SUPP_API_KEY
# Python: os.environ["SUPP_API_KEY"]Key security features
Hashed storage
Only the SHA-256 hash is stored. The raw key is shown once at creation and can never be retrieved again.
Domain restrictions
Lock a key to specific domains. Requests from unauthorized origins are rejected, even with a valid key.
Spend caps
Each key has a configurable daily spend limit (default $5/day). A stolen key can only cause limited damage.
Key rotation
Revoke and regenerate keys anytime from the dashboard. We recommend rotating keys periodically.
Scopes
Each API key has scopes that control which endpoints it can access. Publishable keys are always limited to the widget scope.
| Scope | Access | Default For |
|---|---|---|
| widget | /api/widget/* only | Publishable keys |
| read | GET on dashboard routes | Secret keys |
| write | POST/PATCH/DELETE on dashboard routes | Secret keys |
| admin | Key management, billing, team, integrations | Secret keys (full access) |
Configuring domain restrictions
After generating a key, lock it to your domains so it cannot be used from other sites:
curl -X PATCH https://api.supp.support/api/keys \
-H "Content-Type: application/json" \
-H "Cookie: <session>" \
-d '{
"key_id": "your-key-uuid",
"allowed_domains": ["yourapp.com", "app.yourapp.com"]
}'When domains are configured, requests without an Origin header (e.g. from curl or a server) are rejected. This prevents stolen widget keys from being used outside a browser.