# Verified by Toni: sandbox integration testing

Updated September 20, 2026. General guide: https://www.vbtoni.com/developers/docs

The verified HTTPS sandbox workflow below requires the corresponding backend domain-policy and partner-key changes in the target environment. This document does not establish deployment or hosted acceptance.

## Setup

Choose the tenant flow first under Toni button design in API Credentials. Use Login only when Toni is only the account bridge at entry and identity verification happens later in your app. Use Sign in or register when your entry point should offer both returning-user sign-in and new Toni account creation. Copy the matching embed and AI instructions for that exact flow. The combined option uses two real links and hosted v2 styling; a hosted SVG by itself cannot provide two clickable actions. Login-only variants include mascot buttons in white, blue, black, gray and red, plus wider clean provider-style bars with the compact Toni mark on the left. Old blue, charcoal, white and soft artwork URLs and v1 embeds continue working for existing integrations. Do not use the legacy widget.js. Creating credentials does not install the control on your site.

Create test credentials in your workspace. Choose Localhost only for local callbacks, for example http://localhost:3000/auth/callback. For hosted staging, first verify a website owned by your workspace under Website connections, then select that verified website when creating sandbox credentials. This binds the test app to that website through the existing domainId argument. Localhost callbacks remain allowed; hosted callbacks must use HTTPS and match the bound verified domain. Other domains and invalid or revoked proofs are rejected. Root and www share a website connection; other subdomains need their own proof and binding. Register the exact callback shown in your app, including its path.

Existing localhost-only test apps need new sandbox credentials with a website selected at creation to use hosted HTTPS callbacks. Test apps cannot start paid identity checks. Do not assume test keys automatically return an approved identity or validate production billing.

Under Sandbox, select Create credentials, choose Localhost only or a verified website, save the one-time client secret on your application's server, then continue to Redirect URLs. For a bound staging website, register an exact callback such as https://events-staging.example.com/auth/callback using your own verified hostname. Use Edit redirect URLs for existing credentials. A missed secret cannot be retrieved: Replace client secret issues a new one after confirmation and immediately invalidates the old one. The client ID and callback settings stay unchanged. Never paste secrets into AI prompts or frontend code.

The button and callback must be implemented in your application. Creating a key does not install Toni on your site.

Browser authorization starts at https://login.vbtoni.com/oauth/authorize in hosted environments. For a local Toni checkout, use that checkout's local origin instead. Toni's live issuer, token endpoint, JWKS, and discovery document remain on https://www.vbtoni.com.

## Authorization

The approved designs are Framed Pair (B) and Soft Duo (C). Both offer two separately framed full-row links: Sign in with Toni and Register with Toni. Borders are 1px; Soft Duo has white text on the blue registration row. In API Credentials choose the style and copy its complete embed and matching prompt. The two-row control uses https://www.vbtoni.com/api/brand/button-styles/v2 and the hosted white mascot. Permit https://www.vbtoni.com in style-src and img-src CSP. Do not inline or locally copy these assets. Compatible v2 styling updates refresh centrally after the five-minute asset cache window. No credentials or callback changes are needed. Old v1 embeds and the old artwork URLs remain supported; adopting the new two-row markup requires one embed replacement. Keep both partner-owned links, keyboard focus styling and visible labels. Never wrap the group in another link/button or flatten it into an image. With React, use className and put the stylesheet link in the page head once. Plain links remain usable if styling is unavailable. New markup or authentication changes can still require a deliberate integration update.

Choose Login only, Register, or Sign in or register in the button designer. The Register embed uses `/api/auth/toni/start?intent=register`. Your server must add `screen_hint=signup` to the Toni authorization request for that intent; only sign-in links omit it. This opens email registration directly while preserving the OAuth callback. The artwork query changes only the label, not routing. Use the matching AI instructions to update both the link and start route; never link directly to `/signin`. Both buttons can use the same client ID and callback, with fresh state, nonce, and PKCE per attempt. Existing signed-in users reuse their identity. Identify callback users by issuer and subject, never merge solely by email, and complete your own site's registration requirements for new accounts.

Login only is authentication, not verification. After a valid callback, you may create an authenticated-but-unverified local session for onboarding. Do not unlock protected features that require identity or age until Toni returns server-validated claims that satisfy your requirements.

The hosted Toni auth screen supports a presentation-only `theme=light` option. Add `theme=light` to the `https://login.vbtoni.com/oauth/authorize` request when you want the white-page/light-card shell; omit it for the default dark shell. This only changes the Toni-hosted sign-in appearance and must not be used for account matching, verification, or access decisions.

GET https://login.vbtoni.com/oauth/authorize with:
- client_id: your pk_test_ client ID
- redirect_uri: the exact registered callback
- response_type: code
- scope: openid id_verification (add email/profile only when needed)
- state: fresh cryptographically random value for this attempt
- nonce: fresh random value
- code_challenge: base64url SHA-256 of a fresh PKCE verifier
- code_challenge_method: S256

Store state, nonce, verifier, callback, and intended local account in your server-side session using a secure HttpOnly cookie. Do not treat browser storage as a universal fix for session or state errors.

## Callback and exchange

Handle error responses. Validate and consume state against that pending session before exchange. Reject mismatched or missing state.

POST https://www.vbtoni.com/api/oauth/token from your server with JSON:
```json
{
  "grant_type": "authorization_code",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_SERVER_ONLY_SECRET",
  "code": "CALLBACK_CODE",
  "redirect_uri": "EXACT_CALLBACK",
  "code_verifier": "SAVED_PKCE_VERIFIER"
}
```

Never put the client secret in frontend code or log secrets, codes, or tokens. Reject non-successful responses.

## Signed result

Read trusted configuration from https://www.vbtoni.com/.well-known/openid-configuration.
Validate the ID token with Toni's published JWKS, pinned issuer, your exact client ID as audience, RS256 signature, expiration, saved nonce, and type=id_token. Require verification_status=VERIFIED and evaluate required check results before granting access.

The sub claim is partner-app-scoped. Email and name are optional scope-dependent fields. Raw ID photos and biometric images are not shared. Existing results may require additional or recent checks; they are not permanent universal clearance.

Use the authorization callback and token exchange. There is no published partner webhook subscription API or Toni Node SDK webhook helper.

## Billing and acceptance

Business setup currently includes a $5 verification-credit purchase. Paid verification sessions start at $0.50, with optional checks priced a la carte. Payments are one-time, not subscriptions. The workspace funds checks it requests for its users. Eligible reuse has no new verification charge. Executed declined checks can still be charged.

Test denied consent, invalid state, reused or expired codes, callback mismatch, insufficient coverage, and revoked access. Production acceptance additionally requires a real payment, verification, and itemized billing reconciliation on the registered live site.
