{"openapi":"3.1.0","info":{"title":"OneTrial API","version":"1.0.0","description":"One call that answers whether a signup should get a free trial: allow, challenge, or deny. Every error is { error: { code, message, fix } }; act on `fix`."},"servers":[{"url":"https://onetrial.dev"}],"security":[{"apiKey":[]}],"tags":[{"name":"Decisions"},{"name":"Challenges"},{"name":"Lists"},{"name":"Webhooks"},{"name":"Integration"},{"name":"Settings"},{"name":"Device auth"}],"paths":{"/api/v1/visitor-token":{"post":{"tags":["Decisions"],"security":[],"summary":"Mint a visitor token (called by the browser snippet)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["publicKey","deviceId"],"properties":{"publicKey":{"type":"string"},"deviceId":{"type":"string"},"signals":{"type":"object"}}}}}},"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"type":"object","properties":{"visitorToken":{"type":"string"},"expiresIn":{"type":"integer"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/decisions":{"post":{"tags":["Decisions"],"summary":"Score a signup and return a decision","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionRequest"}}}},"responses":{"200":{"description":"Decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Decision"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Decisions"],"summary":"List decisions","parameters":[{"name":"decision","in":"query","schema":{"type":"string","enum":["allow","challenge","deny"]}},{"name":"email","in":"query","schema":{"type":"string"},"description":"Exact address or domain suffix"},{"name":"days","in":"query","schema":{"type":"integer","default":30}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"Page","content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"type":"array","items":{"$ref":"#/components/schemas/DecisionSummary"}},"nextCursor":{"type":["string","null"]}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/decisions/{id}":{"get":{"tags":["Decisions"],"summary":"Get one decision","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Decision detail"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/decisions/{id}/feedback":{"post":{"tags":["Decisions"],"summary":"Label a decision as false or true positive","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label"],"properties":{"label":{"type":"string","enum":["fp","tp"]},"note":{"type":"string"}}}}}},"responses":{"201":{"description":"Recorded"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/signals/card":{"post":{"tags":["Challenges"],"summary":"Push a card fingerprint collected on your own Stripe account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decisionId","cardFingerprint"],"properties":{"decisionId":{"type":"string"},"cardFingerprint":{"type":"string"}}}}}},"responses":{"200":{"description":"Re-scored (if a challenge was pending) or recorded"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/c/{challengeId}":{"get":{"tags":["Challenges"],"security":[],"summary":"Visitor-safe challenge status","parameters":[{"name":"challengeId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ challengeId, status, options, workspaceName }"}}}},"/api/v1/challenges/{id}/complete":{"post":{"tags":["Challenges"],"summary":"Headless: report the outcome of your own verification UI","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["method","outcome"],"properties":{"method":{"type":"string","enum":["require_card","email_verify","sms_verify","captcha"]},"outcome":{"type":"string","enum":["passed","failed"]},"cardFingerprint":{"type":"string"},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Outcome (with previous/rescored scores for cards)"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already resolved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/allowlist":{"get":{"tags":["Lists"],"summary":"List allowlist entries","responses":{"200":{"description":"{ items }"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Lists"],"summary":"Add a allowlist entry","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","value"],"properties":{"type":{"type":"string","enum":["email","domain","device","ip","card"]},"value":{"type":"string"}}}}}},"responses":{"201":{"description":"Entry"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Lists"],"summary":"Remove a allowlist entry","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/blocklist":{"get":{"tags":["Lists"],"summary":"List blocklist entries","responses":{"200":{"description":"{ items }"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Lists"],"summary":"Add a blocklist entry","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","value"],"properties":{"type":{"type":"string","enum":["email","domain","device","ip","card"]},"value":{"type":"string"}}}}}},"responses":{"201":{"description":"Entry"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Lists"],"summary":"Remove a blocklist entry","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List endpoints (add ?deliveries=<id> for its delivery log)","responses":{"200":{"description":"Endpoints"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"summary":"Register an endpoint; the signing secret is returned once","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["decision.created","challenge.completed","challenge.failed"]}}}}}}},"responses":{"201":{"description":"{ id, url, events, secret }"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Remove an endpoint","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integration/status":{"get":{"tags":["Integration"],"summary":"Machine-readable integration checklist","responses":{"200":{"description":"Checklist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationStatus"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/settings":{"get":{"tags":["Settings"],"summary":"Workspace settings","responses":{"200":{"description":"Settings"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Settings"],"summary":"Update thresholds, shadow mode, stack, plan price","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"thresholds":{"type":"object","properties":{"allow":{"type":"integer"},"challenge":{"type":"integer"}}},"shadowMode":{"type":"boolean"},"planPriceCents":{"type":"integer"},"stack":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keys":{"post":{"tags":["Settings"],"summary":"Create another API key","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["test","live"],"default":"test"}}}}}},"responses":{"201":{"description":"{ key, id, mode, publicKey }"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Plan limit reached (Free) or rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/device/code":{"post":{"tags":["Device auth"],"security":[],"summary":"Start device authorization (CLI/MCP)","responses":{"200":{"description":"{ device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval }"}}}},"/api/device/token":{"post":{"tags":["Device auth"],"security":[],"summary":"Poll for the approved API key","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}}}}},"responses":{"200":{"description":"{ apiKey, publicKey, workspaceId }"},"410":{"description":"expired_token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"428":{"description":"authorization_pending","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"ot_test_... or ot_live_... from the dashboard"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","fix"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"fix":{"type":"string","description":"Exact corrective step"}}}}},"DecisionRequest":{"type":"object","required":["email","ip"],"properties":{"visitorToken":{"type":"string","description":"From OneTrial.getToken() in the browser. Missing or tampered is a signal, not an error."},"email":{"type":"string"},"ip":{"type":"string","description":"Client IP (x-forwarded-for)"},"cardFingerprint":{"type":"string","description":"Stripe payment_method.card.fingerprint from YOUR account"},"userId":{"type":"string","description":"Your user id; groups events into one account in the identity graph"},"metadata":{"type":"object"}}},"Decision":{"type":"object","properties":{"decisionId":{"type":"string"},"decision":{"type":"string","enum":["allow","challenge","deny"]},"score":{"type":"integer","minimum":0,"maximum":100},"reasons":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"weight":{"type":"number"}}}},"challengeOptions":{"type":"array","items":{"type":"string","enum":["require_card","email_verify","sms_verify","captcha"]}},"challengeId":{"type":"string"},"challengeUrl":{"type":"string","format":"uri"},"shadow":{"type":"boolean","description":"True while the workspace is in shadow mode (decision is always allow)"},"wouldBe":{"type":"string","enum":["allow","challenge","deny"]},"usage":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer"},"warn":{"type":"boolean"}}}}},"DecisionSummary":{"type":"object","properties":{"decisionId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"email":{"type":"string"},"score":{"type":"integer"},"decision":{"type":"string"},"enforcedDecision":{"type":["string","null"]},"shadow":{"type":"boolean"},"reasons":{"type":"array","items":{"type":"object"}}}},"IntegrationStatus":{"type":"object","properties":{"workspaceId":{"type":"string"},"mode":{"type":"string","enum":["shadow","live"]},"complete":{"type":"boolean"},"checklist":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"done":{"type":"boolean"},"detail":{"type":"string"},"fix":{"type":"string"}}}},"counts":{"type":"object"}}}}}}