Keep a free tier without bleeding GPU
Email and phone heuristics don't stop credit farming. Disposable inboxes and virtual-number services beat them in seconds, and the cost lands on your inference bill. Gate the free tier on the device instead: one machine gets one trial, and it survives email and phone churn without a credit-card wall that tanks conversion.
The integration
Two touch points: the free-tier signup, and (optionally) each free-quota grant.
import { RootHerald } from "@rootherald/node";
const rh = new RootHerald({ secretKey: process.env.RH_SECRET_KEY! }); // rh_sk_…
// Earlier: GET /signup/challenge -> rh.issueChallenge() -> relay nonce to the client.
// The dumb client quotes over the nonce and posts back { challengeId, evidence }.
const verdict = await rh.verify(body.evidence, {
challengeId: body.challengeId,
policy: "rootherald:builtin:strict-hardware",
});
// Don't hard-block by default — treat a non-pass as a downgrade, not a wall:
// fall back to your existing flow (card required, etc.)
if (verdict.device.verdict !== "pass") {
return res.status(403).json({ error: "device_unverified", retryWith: "payment_method" });
}
const prior = await freeTrials.findByDevice(verdict.device.ueid);
if (prior) return res.status(409).json({ error: "free_trial_already_used_on_device" });
await freeTrials.create({ deviceId: verdict.device.ueid, userId, grantedCredits: FREE_CREDITS });Because verdict.device.ueid is stable per tenant, the farmer who churns through 500 throwaway emails on one box still only ever gets one free trial. Spinning up cloud VMs is the next-cheapest move, and those classify as cloud-vtpm classes that the default policy rejects.
Posture for licensing defensibility
If you're negotiating content licences (music, image, code), "we know our users" matters. The attestation gives you a defensible answer without collecting more PII: each free account maps to a distinct, real device, and you store nothing about that device beyond an opaque per-tenant pseudonym.