OneTrial docs

One API call answers "should this signup get a free trial?" with allow, challenge, or deny. Integration takes a snippet, one server call, and a webhook.

How it works

  1. The browser snippet (https://onetrial.dev/v1.js, 15 KB gzipped, async) computes a device hint and passive signals and exchanges them for a signed visitorToken (JWT, 5-minute TTL). It never shows UI.
  2. On form submit, your frontend reads await OneTrial.getToken() and sends it with the signup to your backend.
  3. Your backend calls POST /api/v1/decisions with the token, email, and client IP (plus cardFingerprint and userId when you have them).
  4. You get { decision: "allow" | "challenge" | "deny", score, reasons[], challengeOptions[], challengeId?, challengeUrl? }.
    • allow: create the trial.
    • challenge: send the visitor to challengeUrl (hosted) or run the headless flow; unlock the trial on the challenge.completed webhook.
    • deny: show a paid plan or a support contact. Never expose score or reasons to the visitor.
  5. New workspaces start in shadow mode: every signup is scored and recorded but the API returns allow (shadow: true, wouldBe: "..."). Flip to live from the dashboard or PATCH /api/v1/settings {"shadowMode": false}.
Secrets: ot_test_... / ot_live_... keys are server-side only. ot_pk_... is public and goes in the snippet.

Install paths

  • With an AI agent: run npx onetrial init in your project, or paste the prompt from Agent prompts.
  • By hand: pick a quickstart.
  • Verify: GET /api/v1/integration/status returns a checklist; nothing is done until it says so.
Machine-readable: llms.txt · llms-full.txt · openapi.json