Skip to main content

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:

TypePrefixUse fromPermissions
Publishableqv_pub_*Browser, widget, public clientInit verifications, submit captures
Secretqv_sec_*Server-side onlyAll 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:

EnvironmentPublishableSecretBehavior
Testqv_pub_test_*qv_sec_test_*Free, real ML pipeline, no billing impact
Liveqv_pub_*qv_sec_*Real billing, real verifications

Recommended workflow:

  1. Build and integrate against test keys
  2. Run test verifications until you're happy with the flow
  3. 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:

  1. Go to API keys
  2. Click Rotate on the key you want to replace
  3. The new key is shown once — copy it
  4. Update your code / environment
  5. The old key continues working for 15 minutes to give you a deployment window
  6. 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

HTTPError codeWhat it means
401unauthorizedMissing or malformed Authorization header
401invalid_keyKey doesn't exist, expired, or was revoked
403origin_not_allowedRequest from a domain not in the allowed origins list
403wrong_environmentTest key used against live endpoint or vice versa
429rate_limitedToo many requests — see Rate limits

See Errors for the full error catalog.

What's next