{"openapi":"3.1.0","info":{"title":"VerifyYou API","description":"The external surface — API-key authed.","version":"v3"},"paths":{"/v3/initialize":{"post":{"tags":["Verification Flow"],"summary":"Initialize a verification session","description":"Queue up a run before the person verifies and get back a hosted verification link plus the `session_id` your frontend opens. They return to `redirect_url` if you passed one, else the verification's saved redirect URL, with `?vyt=<token>&vyc=<0|1>` appended — confirm that token server-side at `GET /v3/confirmations/{token}`. Accepts a publishable key (browser) or a secret key (server); identifiers, targeting and `redirect_url` need the secret key (and `redirect_url` and `group` need a session, so they cannot be combined with the deprecated `expire_in_days`); `config` needs a test key.","operationId":"Verification Flow-initialize","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitializeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitializeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v3/confirmations/{token}":{"get":{"tags":["Confirmations"],"summary":"Confirm a verification result","description":"Exchange the `vyt` token from the return URL for the authoritative verdict. A token minted for another company — or the other test/live partition of your own keys — reads as nonexistent. Secret key only.","operationId":"Confirmations-get_confirmation","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/confirmations/{token}/lock":{"post":{"tags":["Confirmations"],"summary":"Consume a verification result","description":"Single-use enforcement: mark the pass consumed. A locked pass reads as not-passed everywhere, so the person re-verifies on their next run — one pass, one use. Idempotent. Secret key only.","operationId":"Confirmations-lock","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/confirmations":{"post":{"tags":["Confirmations"],"summary":"Look up a verification result by identity","description":"The token-free read: the person's latest settled pass with you, found by the credential you already hold. For when no token reached you — they closed the tab before the redirect, or the run had no redirect at all (an emailed invite they finished on their phone). `GET /v3/confirmations/{token}` stays the stronger check: a token proves THIS run just finished and came back to you, while this answers the looser question of where the person stands. Scoped to your company and your key's test/live partition — it can never see anyone else's traffic. 404 when that credential has never settled a pass with you. Secret key only.","operationId":"Confirmations-lookup_confirmation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationLookupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v3/keys/test":{"post":{"tags":["API Keys"],"summary":"Test an API key (deprecated)","description":"**Deprecated.** Check that an API key works and see what it is: publishable or secret, test or live, and which company it belongs to. Send the key as the bearer token, like any other call. Always returns `200`: a bad key comes back as `valid: false` rather than an error, so it's safe to wire into a healthcheck or setup step.","operationId":"API Keys-test_key","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyTestResponse"}}}}},"deprecated":true,"security":[{"HTTPBearer":[]}]}},"/v3/test/confirmation-token":{"post":{"tags":["Testing"],"summary":"Mint a test confirmation token","description":"Settle a REAL test pass with the verdict you choose and get its `vyt` — no flow run needed, useful for exercising the confirmation exchange from a test suite. The pass lands in your test partition and dies with normal test-data cleanup; live keys can never see it. Test secret key only (`sk_test`).","operationId":"Testing-create_test_confirmation_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestConfirmationTokenRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestConfirmationTokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"ConfirmationLookupRequest":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"The person's email, as you sent it to `initialize`.","examples":["user@example.com"]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"The person's phone, as an alternative."},"verification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Verification Id","description":"Narrow to one verification. Omit to read across all of yours."},"group":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Group","description":"Narrow to one group — where the person stands in THAT pool. Omit to read across every group, runs carrying none included."}},"type":"object","title":"ConfirmationLookupRequest"},"ConfirmationResponse":{"properties":{"verified":{"type":"boolean","title":"Verified","description":"Authoritative result: true only if the verification passed and the pass is unlocked. Gate access on this, never on the client-side `vyc` hint."},"id":{"type":"string","title":"Id","description":"**Deprecated.** The pass id for this person's run through the verification.","deprecated":true},"status":{"type":"string","title":"Status","description":"Verdict detail: approved or denied — approved WITH reasons is 'flagged'."},"reasons":{"items":{"type":"string"},"type":"array","title":"Reasons","description":"Rule findings behind the status; a denied pass always carries at least one, an approved pass with reasons passed with findings."},"confirmed_at":{"type":"string","format":"date-time","title":"Confirmed At","description":"**Deprecated.** When the verdict settled.","deprecated":true},"locked":{"type":"boolean","title":"Locked","description":"**Deprecated.** You consumed this pass via the lock endpoint — it reads as not-passed.","deprecated":true},"declined":{"type":"boolean","title":"Declined","description":"The person chose not to scan — a denied pass, but not a failed one.","default":false},"is_test":{"type":"boolean","title":"Is Test","description":"**Deprecated.** Settled by a test run.","deprecated":true},"score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Score","description":"**Deprecated.** Trust score, 0-100 higher = riskier.","deprecated":true},"band":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Band","description":"**Deprecated.** Trust band the score landed in.","deprecated":true},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Id","description":"**Deprecated.** Your own id for the run, when `initialize` was called with one.","deprecated":true},"group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group","description":"The uniqueness pool the run was judged in and settled into, when `initialize` was called with a `group`. Null for a run that carried none."},"groups":{"items":{"type":"string"},"type":"array","title":"Groups","description":"The groups this person was found in: the pools whose prior history produced the findings behind `reasons` — the run's own `group` for an in-pool hit, an included group when `initialize` widened the pool with `include_groups`. Populated for flagged passes too. Empty when nothing hit, or the offending history was ungrouped."},"identity":{"anyOf":[{"$ref":"#/components/schemas/RevealedIdentityView"},{"type":"null"}],"description":"**Deprecated.** The proven identity, present only when the verification's config enables reveal and the run proved a credential. Null otherwise — never absent.","deprecated":true}},"type":"object","required":["verified","id","status","confirmed_at","locked","is_test"],"title":"ConfirmationResponse"},"ConfirmationStatus":{"type":"string","enum":["approved","denied"],"title":"ConfirmationStatus","description":"Binary: APPROVED = exit unblocked; DENIED = exit blocked. There is no\npending status — rows are born settled (the in-flight run lives on the\nsession, never in this table) — and no flagged status: \"flagged\" is\nPRESENTATION, derived downstream as approved-with-reasons."},"CreateTestConfirmationTokenRequest":{"properties":{"status":{"$ref":"#/components/schemas/ConfirmationStatus","description":"The verdict the test pass settles with.","default":"approved"},"reasons":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Reasons","description":"Rule findings to settle the pass with (e.g. `collision_company`, `identity_mismatch`). Unknown reasons are rejected."},"verification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Verification Id","description":"The verification to settle under; your default verification when omitted."}},"type":"object","title":"CreateTestConfirmationTokenRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InitializeRequest":{"properties":{"verification_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Verification Id","description":"Secret key only. Target a verification directly instead of running the company's default verification."},"verification_external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verification External Id","description":"**Deprecated.** Target by `verification_id` instead. Still accepted: your own external id for the verification, as an alternative to `verification_id`.","deprecated":true,"examples":["signup-flow"]},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Secret key only. Seed the run with a provided identity — the flow is locked to it and can never collect a different one.","examples":["user@example.com"]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"Secret key only. Seed the run with a provided phone identity."},"external_id":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"External Id","description":"Secret key only. Your own id for this run — carried through the flow and returned on the confirmation so you can tie the result back to your records.","examples":["user-8842"]},"external_tracker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Tracker","description":"**Deprecated.** Accepted for wire compatibility; not recorded.","deprecated":true},"group":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Group","description":"Secret key only. Your own id for the uniqueness pool this run belongs to, so one verification can be reused across separate groups. A run carrying a group is judged only against passes in the same group — the same person can pass once per group without colliding with themselves — and the group is recorded on the confirmation. Omit it and the run is judged against everything, as before. Groups need no registration; whatever id arrives is the pool. Keep `external_id` per person, not per group: it is an identity, and a second one on a known face is a duplicate account whatever group it arrives in.","examples":["spring-intake"]},"include_groups":{"anyOf":[{"items":{"type":"string","maxLength":255,"minLength":1},"type":"array","maxItems":50,"minItems":1},{"type":"null"}],"title":"Include Groups","description":"Secret key only. Other group ids whose history also counts against this run: every uniqueness read — collision edges, denied history, pass metering — widens from `group` alone to `group` plus these, while the run still settles into `group` and never writes to an included one. What a cross-group hit does is decided by the verification's existing levers (`collision.action`, `limit.kind`), exactly as within a group. Repeats and your own `group` in the list are harmless, and without `group` this adds nothing — an ungrouped run is judged against everything already.","examples":[["spring-intake","winter-intake"]]},"redirect_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect Url","description":"Secret key only. Where the person lands when this run ends, with the result appended as `?vyt=<token>&vyc=<0|1>`. Takes precedence over the redirect URL saved on the verification. Must be absolute and https, except on localhost or a private address, where http is accepted so you can point it at a dev server.","examples":["https://yourapp.com/verified","http://localhost:3000/verified"]},"pass_params":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Pass Params","description":"Extra query params carried through the flow and appended to the return URL. Reserved `vy*` keys are ignored."},"expire_in_days":{"anyOf":[{"type":"integer","maximum":365.0,"minimum":1.0},{"type":"null"}],"title":"Expire In Days","description":"**Deprecated — the number you pass is ignored.** Invites stopped expiring when `verification_invites.expires_at` was dropped, so this survives only as the switch that mints a durable invite instead of a one-shot session; any value in range behaves identically. Requires `email`. The link stays claimable until redeemed or revoked, and resumes where the person left off. The response carries `invite_id` instead of `session_id`. Kept because `/v3` is append-only — it goes away when the next external version is minted.","deprecated":true},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Test key only. Override the verification's stored config for THIS run. The override is used verbatim — never merged with the stored config — and dies with the run. Rejected with a live key."},"auto_return":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Return","description":"Return to `redirect_url` the instant an approved (or declined) check settles, instead of showing the result screen with a return button. Works with any key — it is a return-behavior lever, not a config override. Overlays the verification's stored `returning.auto_return` for THIS run only. Ignored by invite links, which never auto-return."}},"type":"object","title":"InitializeRequest"},"InitializeResponse":{"properties":{"url":{"type":"string","title":"Url","description":"Hosted verification link with a queued-up run. Redirect the person here.","examples":["https://app.verifyyou.com/verification?vys=..."]},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id","description":"The minted session, for a plain initialize. Null when `expire_in_days` was set."},"invite_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Invite Id","description":"**Deprecated.** The durable invite, only when the deprecated `expire_in_days` was set.","deprecated":true}},"type":"object","required":["url"],"title":"InitializeResponse"},"KeyTestResponse":{"properties":{"valid":{"type":"boolean","title":"Valid","description":"Whether the key resolved to an active account. An unknown or revoked key comes back as `false`, not an error."},"key_type":{"type":"string","title":"Key Type","description":"Prefix of the key you sent: `pk_live`, `pk_test`, `sk_live`, `sk_test`, or `unknown` if it matched none of them.","examples":["sk_test"]},"is_test":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Test","description":"Whether the key is a test key. `null` when the key didn't resolve."},"customer_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Customer Id","description":"The company the key belongs to. `null` when the key didn't resolve."}},"type":"object","required":["valid","key_type"],"title":"KeyTestResponse"},"RevealedIdentityView":{"properties":{"provider":{"type":"string","title":"Provider","description":"The credential's channel: email, phone, or test."},"identifier":{"type":"string","title":"Identifier","description":"The proven identifier itself."}},"type":"object","required":["provider","identifier"],"title":"RevealedIdentityView"},"TestConfirmationTokenResponse":{"properties":{"token":{"type":"string","title":"Token","description":"A real `vyt` for a real test pass. Exchange it at `GET /v3/confirmations/{token}` with the same test secret key."},"verified":{"type":"boolean","title":"Verified","description":"The `verified` value the exchange will report for this token."}},"type":"object","required":["token","verified"],"title":"TestConfirmationTokenResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}