Authentication
Two key types, one principle - secrets stay on the server, public keys go in the browser.
Two key types
| Type | Prefix | Where it lives | Use for |
|---|---|---|---|
| Secret key | sk_test_…, sk_live_… |
Your server (env var, secrets manager) | Server-to-server API calls |
| Public widget key | pk_test_…, pk_live_… |
Your customer's website HTML | Embedded widgets that visitors interact with |
sk_… in browser code. Anyone with a secret key can read/write your tenant's data.Secret keys
Create in the dashboard → service → Developers → Create key. Pick a name, environment, scopes.
Use with a Bearer header:
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx
You'll see the full secret once at creation. Copy it to your secrets manager immediately - we don't store it in plaintext (SHA-256 hashed at rest).
Public keys
Issued per-service in the dashboard, locked to an origin allowlist. Used by the widget loader.
<script src="https://app.softsolz.uk/softsolz.js"
data-public-key="pk_live_xxxxxxxxxxxx"
data-service-id="forms"
data-form-slug="contact-us"></script>
A request from a non-allowlisted origin is rejected - even with a stolen key, an attacker can't load your widget on their site.
Scopes
Each key carries a list of scopes like service.forms.submit. The platform checks each call's required scope against the key's set.
- Least privilege - only tick scopes the key actually needs.
- You can't grant scopes your role doesn't have - prevents accidental privilege escalation.
- The wildcard
*is reserved for platform super-admins.
Environments
Every workspace has a paired sandbox. Sandbox keys (sk_test_… / pk_test_…) write to the sandbox tenant. No real Stripe / email side-effects ever fire in sandbox.
Rotation
Two paths:
- Revoke - kills the key immediately. Existing callers get 401.
- Rotate webhook secret - creates a new signing secret while the old one stays valid for 7 days. Lets you re-deploy without a deliveries gap.
Auth errors
| Status | Body | Meaning |
|---|---|---|
| 401 | missing_authorization | No Bearer header. |
| 401 | invalid_api_key | Key revoked or unknown. |
| 403 | insufficient_scope | Key doesn't have the required scope. |
| 403 | origin_not_allowed | Public key called from a non-allowlisted origin. |
| 402 | service_inactive | The service subscription lapsed. |
| 429 | rate_limit_exceeded | Slow down - check X-RateLimit-Remaining. |