Files
hanzo.ai/app/(marketing)/idv/page.tsx
zooqueen 75c4f1f641 One product answers with one name, route, command and docs page
The CLI lines on the product pages were written from the product name -- hanzo
dns zones, hanzo kms keys -- and several were not commands the binary has. So the
command moves into lib/product.ts, which assembles the rest from what is already
stated: the catalog names the product and its route, pages.json names what the
catalog does not carry, and products-metadata answers for docs, where null means
docs publishes nothing and the link drops.

Every CLI line in that table was run against the binary. A product absent from it
has no command and its page prints none; nothing composes a verb out of a name.
Both blocks that draw it import the Product type rather than declaring their own,
which leaves the table the only place a command can be written.

The catalog also moves out of package.json into pnpm-workspace.yaml, where pnpm
reads it, so the versions are stated once.
2026-09-06 23:18:24 -07:00

73 lines
4.1 KiB
TypeScript

'use client'
import { ArrowRight, Activity, Building2, FileText, Globe, ShieldCheck, UserCheck } from 'lucide-react'
import { ProductLanding } from '@/components/product/ProductLanding'
import { ProductFooter } from '@/components/products/ProductFooter'
/**
* Hanzo IDV, through the ONE product kit.
*
* authz, hsm and idv were a third-generation copy of the same page: a plain
* `<h1>` hero, a feature grid with NO heading above it, and a "Get started
* with X" card. See LLM.md, "Tailwind is NOT gone".
*
* EVERY WORD IS THE ONE THAT WAS HERE. The headless grid is why a section head
* is now optional in the kit rather than required — these three never had one,
* and writing three would be writing words nobody chose.
*/
export default function HanzoIDVPage() {
return (
<>
<ProductLanding
title={"Hanzo IDV"}
lede={"Hanzo IDV is one interface in front of the identity-verification vendors, so which vendor you use is a line of configuration rather than a rewrite of your onboarding. It does not verify anybody itself. It starts a check with the provider you chose, reads the verdict back, and proves that a callback came from them and not from someone who guessed the URL. Jumio and Onfido work end to end today; Plaid works by polling; the rest refuse until their response parsing is written, which is stated here because a verification service that guesses is worse than one that says it cannot tell."}
ctas={[
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
]}
what={{
pillars: [
{
icon: UserCheck,
title: "Four calls, whichever vendor",
body: "Start a verification, check its status, parse a webhook, name yourself. Every provider implements the same four, so swapping one for another is configuration and not a rewrite of your onboarding.",
},
{
icon: Building2,
title: "A verdict, or nothing",
body: "A provider whose response we do not parse refuses rather than answering. Two of them used to return approved without reading the reply — one for any response that was not an error, the other including a rejected document. Anything gating on that would have admitted an unverified person, so both now refuse until the parsing is written.",
},
{
icon: ShieldCheck,
title: "A webhook has to prove it is one",
body: "Signatures are HMAC-SHA256 over the raw body, compared in constant time, with the header matched case-insensitively because the wire spelling and the canonical spelling differ. An empty signing secret is a refusal, never a skip — an HMAC under a key everybody knows is one anybody can compute.",
},
{
icon: FileText,
title: "Polling where a callback cannot be trusted",
body: "Every result is verified before it counts. A webhook whose signature we can check is accepted; anything else is polled from the provider directly, so the verdict always comes from the source.",
},
{
icon: Activity,
title: "Credentials come from KMS",
body: "The API token bills per check and the webhook token is what separates a provider's verdict from a forgery, so neither is a literal in the code and neither falls back to an environment variable. A missing secret fails at construction rather than producing a provider that quietly runs without one.",
},
{
icon: Globe,
title: "Verification is not screening",
body: "Proving somebody is who they say is a different job from watching what they do afterwards. Sanctions lists, transaction monitoring, cases and the five-year record clock live in Hanzo Risk, and this does not duplicate them.",
},
],
}}
finalCta={{
title: "Get started with IDV",
buttons: [
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
],
}}
/>
<ProductFooter slug={"idv"} name={"IDV"} />
</>
)
}