Authentication
Veridia uses bearer token authentication. Every API request (except /health) needs an Authorization header:
Authorization: Bearer qv_pub_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9
Key types
There are two kinds of keys, with different security properties:
| Type | Prefix | Use from | Permissions |
|---|---|---|---|
| Publishable | qv_pub_* | Browser, widget, public client | Init verifications, submit captures |
| Secret | qv_sec_* | Server-side only | All publishable scopes + fetch verdicts + decrypt webhook secrets |
The publishable key is safe to expose in your HTML / SPA bundle. It's tied to a specific tenant and a list of allowed origins — it can't be used from a domain that wasn't explicitly whitelisted.
The secret key is never safe to expose. It can fetch verdicts for any verification in your tenant. Treat it like a database password.
Environments
Every tenant gets two parallel sets of keys:
| Environment | Publishable | Secret | Behavior |
|---|---|---|---|
| Test | qv_pub_test_* | qv_sec_test_* | Free, real ML pipeline, no billing impact |
| Live | qv_pub_* | qv_sec_* | Real billing, real verifications |
Recommended workflow:
- Build and integrate against test keys
- Run test verifications until you're happy with the flow
- Switch to live keys in production
Test verifications are stored in the same DB as live ones, but with a flag that excludes them from your billing and statistics.
Domain whitelist (publishable keys)
Each publishable key has an allowed origins list. The widget refuses to load on any domain not in the list.
Set this in your dashboard under API keys → Edit → Allowed origins:
https://yourapp.com
https://staging.yourapp.com
http://localhost:3000
Wildcards like *.yourapp.com are supported.
:::warning Localhost during development
You must explicitly add http://localhost:PORT to the allowed origins for local testing. The widget refuses by default — this prevents leaked keys from being used by attackers running their own localhost.
:::
Using the secret key
Server-side examples:
curl
curl -X GET https://api.xxuxe.online/v1/verify/vf_AG07CDWRRFQV4T05ZXG2 \
-H "Authorization: Bearer qv_sec_YOUR_SECRET"
JavaScript / Node.js
const response = await fetch('https://api.xxuxe.online/v1/verify/' + id, {
headers: {
'Authorization': `Bearer ${process.env.VERIDIA_SECRET_KEY}`,
},
});
const data = await response.json();
Python
import os, requests
response = requests.get(
f"https://api.xxuxe.online/v1/verify/{verification_id}",
headers={"Authorization": f"Bearer {os.environ['VERIDIA_SECRET_KEY']}"},
)
data = response.json()
PHP
<?php
$ch = curl_init("https://api.xxuxe.online/v1/verify/$verificationId");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $_ENV['VERIDIA_SECRET_KEY'],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
Key rotation
Keys can be rotated at any time from the dashboard:
- Go to API keys
- Click Rotate on the key you want to replace
- The new key is shown once — copy it
- Update your code / environment
- The old key continues working for 15 minutes to give you a deployment window
- After 15 minutes, the old key is permanently invalid
For emergency revocation (suspected leak), use Revoke instead — kills the key immediately.
Best practices
- Never commit secret keys to source control. Use environment variables or a secrets manager
- Use separate keys for test and live — never use a live key on staging
- Limit allowed origins to only the domains that need them
- Rotate keys quarterly as a hygiene practice
- Log the request ID from API responses — makes support tickets 10x faster to resolve
- For server-side calls, always use the secret key — never the publishable one
Authentication errors
| HTTP | Error code | What it means |
|---|---|---|
401 | unauthorized | Missing or malformed Authorization header |
401 | invalid_key | Key doesn't exist, expired, or was revoked |
403 | origin_not_allowed | Request from a domain not in the allowed origins list |
403 | wrong_environment | Test key used against live endpoint or vice versa |
429 | rate_limited | Too many requests — see Rate limits |
See Errors for the full error catalog.
What's next
- POST /v1/verify/init — start a verification
- Errors — full error code reference
- Rate limits — limits and quotas