Case Study · Age and risk verification / developer tools
Developer infrastructure for high-risk categories — JWT age tokens, tenant isolation, and usage-based billing without storing identity data.

PII retention
Zero (by design)
Billing
Stripe metered
Tenancy
Full isolation
LoomAPI is a developer-first age and risk verification API built for high-risk digital platforms. Adult content platforms, gambling operators, high-risk SaaS businesses, and payment processors all face the same problem: they are legally required to verify user age but do not want to store sensitive identity data, manage identity provider integrations, or build billing infrastructure from scratch.
LoomAPI's answer is a single API that sits between a platform and its users. A developer makes one API call to start a verification. The user goes through the verification process. LoomAPI issues a time-limited JWT token confirming age status. The platform validates that token on every gated request. No identity documents are stored. No biometric data is retained. The compliance burden moves from each platform to a shared infrastructure layer designed specifically to handle it.
The brief was to build that infrastructure from scratch: the API, the multi-tenant architecture, the billing system, the developer-facing documentation and marketing site, and the admin console.
Age verification is a solved technical problem in isolation. Veriff, Onfido, and others handle document verification reliably. The problem is the integration layer that sits around it.
A platform building age verification from scratch has to handle tenant isolation if it serves multiple clients, implement its own rate limiting and quota management, build billing infrastructure for usage-based pricing, design a data retention policy that satisfies privacy regulations without breaking verification workflows, write developer documentation that lets third-party integrators go live quickly, and build admin tooling to manage tenants, monitor usage, and handle edge cases.
None of these problems are interesting to the platform building them. They are overhead. They are solved problems being solved again, badly, by teams whose expertise is in something else entirely. And when they are done badly in a high-risk category, the consequences are regulatory rather than just commercial.
The deeper problem is that most age verification products are designed around storing verification outcomes tied to user identities. That creates a data liability. A breach does not just expose account data. It exposes evidence that specific individuals have visited specific categories of platform. For the platforms involved, that is a reputation and compliance catastrophe.
The central architectural decision was to make zero retention the default rather than an option. JWT tokens replace raw identity handling at the core of the system. When a verification completes, LoomAPI issues a time-limited token that encodes age status. The platform validates that token on every gated request. At no point does LoomAPI store the user's name, identity documents, facial images, or any PII that would connect a specific person to a specific verification outcome.
This is privacy by architecture rather than privacy by policy. A policy can be violated accidentally or deliberately. An architecture that does not store the data cannot expose it.
Multi-tenancy was designed with full isolation from day one rather than retrofitted. Each tenant has separate API keys, separate rate limits, separate monthly quotas, and separate billing. A tenant cannot observe another tenant's usage, affect another tenant's rate limits, or access another tenant's verification data. The isolation is enforced at the data model level, not just in application logic.
The billing model was built as a product feature rather than a payment system. Stripe metered billing charges per completed verification. There are no setup fees, no seat licenses, and no minimum commitments. Every tenant created through the admin API automatically receives a Stripe customer and usage-based subscription. Usage is reported fire-and-forget per verification so it does not add latency to the API response path. If Stripe is unavailable, the verification API continues to function. Billing and verification are decoupled.
The API is built on Fastify 5 with TypeScript, connected to PostgreSQL via Prisma for the data layer and Redis for rate limiting and quota enforcement. Rate limiting is enforced per tenant at the Redis layer so it is both fast and isolated from the primary database. The system is fail-closed: if Redis is unavailable for rate limiting, the affected endpoints return 503 rather than allowing unmetered traffic through.
Verification providers are abstracted behind a pluggable interface. Mock mode handles development and testing without requiring live credentials. Veriff mode handles real document verification in production. Adding a new provider requires implementing the provider interface without touching the core verification flow.
The monorepo covers four applications. The API handles all verification, tenant management, billing, and token operations. The marketing and documentation site covers developer onboarding, API reference, code examples in Node.js, Python, and PHP, pricing, and legal pages. The admin dashboard gives internal operators visibility across tenants, usage, and billing. The dashboard uses Clerk for authentication with role-based access.
Security was treated as a design constraint rather than a feature. The waitlist endpoint is fail-closed: if the HMAC secret is missing or Redis is unavailable, the endpoint returns 503 rather than allowing unsigned submissions. JWT secrets, admin API keys, and tenant API keys are all environment-gated. Application logs are explicitly prohibited from containing PII. The data retention policy is documented, implemented in the data model, and enforced by the absence of fields rather than by deletion logic.
273 commits. 15,135 files changed across the full history. 41 test and spec files covering unit, integration, and smoke test coverage.
LoomAPI is a complete developer-facing product: a working API, a billing infrastructure, developer documentation, an admin console, and a marketing presence that explains the technical value proposition to the developers who will integrate it.
What this project demonstrates beyond the technical output is a different mode of working. Building an API product for developers to integrate is fundamentally different from building a marketing site for a business owner to show clients. The audience is technical. The documentation is the product. The reliability guarantees are the selling point.
The branding migration from Project Halo to LoomAPI happened mid-build rather than before it. Renaming across a monorepo with four applications, multiple configuration files, and deployed infrastructure is manageable but high-friction. Committing to the final product name before writing a single line of code eliminates that class of problem entirely. For any product with a public API, the name is part of the interface — changing it has downstream consequences for documentation, SDK naming, and any tenants already using the mock environment.
What shipped and in what shape.
Fastify 5, Next.js 14, TypeScript, PostgreSQL, Prisma, Redis, Clerk, Stripe metered billing, Veriff, Turborepo monorepo — zero-retention JWT age tokens, multi-tenant isolation, 273 commits, 41 test files
“An extremely good project lead that's skilled. He knows how to manage people and the work all at the same time.”
If the compliance layer is slowing down your core product, book a call — we can assess what needs to be custom-built and what can be abstracted. Start with the 48-hour audit if you want a clear picture of gaps and next steps first.