ThemysThemys/Docs

POST /api/analyze

Analyze Terms of Service text with AI to get risk scores, flagged clauses, and full extraction.

Endpoint

code
POST /api/analyze

Analyzes Terms of Service text and returns a structured risk assessment including a risk score, summary, flagged clauses, and full extraction breakdown.

Authentication

Include your Clerk session token in the Authorization header:

code
Authorization: Bearer <your_session_token>

Request Body

json
{

"text": "Terms of Service\n\n1. Acceptance of Terms\nBy accessing...",

"sourceUrl": "https://example.com/terms-of-service",

"domain": "example.com"

}

FieldTypeRequiredDescription ------------------------------------ textstringOne of text or urlThe Terms of Service text to analyze urlstringOne of text or urlURL to extract text from (uses /api/extract internally) sourceUrlstringNoOriginal public URL for already-extracted text; used as metadata and never fetched domainstringNoDomain name (e.g., "example.com"). Used for display and grouping in scan history.

Provide exactly one analysis input: text or url. When you already extracted text from a URL, send the text with sourceUrl so the origin is retained without fetching it again.

Response

json
{

"riskScore": 7,

"riskLevel": "red",

"summary": "This Terms of Service grants the company broad rights to user data and content. It includes mandatory arbitration with a class action waiver, unilateral right to modify terms, and a liability cap limited to the amount paid in the last 12 months.",

"flags": [

{

"category": "Data Privacy",

"severity": "high",

"text": "We may share your personal information with third-party partners for marketing and advertising purposes.",

"explanation": "Your personal data can be shared with third parties for advertising without additional consent.",

"riskScore": 8

},

{

"category": "Arbitration",

"severity": "high",

"text": "You agree to resolve any disputes through binding arbitration and waive your right to participate in a class action lawsuit.",

"explanation": "You give up the right to sue in court or join a class action. All disputes go through private arbitration.",

"riskScore": 8

},

{

"category": "Billing",

"severity": "medium",

"text": "We reserve the right to modify pricing at any time with 30 days notice.",

"explanation": "The company can raise your subscription price with just 30 days notice.",

"riskScore": 5

}

],

"fullExtraction": [

{

"title": "Data Privacy",

"keyPoints": [

{

"title": "Third-party data sharing",

"detail": "Collects name, email, IP address, device info, and usage data. Shares data with third-party advertisers.",

"severity": "warning"

},

{

"title": "Data deletion",

"detail": "Users can request data deletion via email.",

"severity": "info"

}

]

}

]

}

Response Fields

Top Level

FieldTypeDescription -------------------------- riskScorenumberOverall risk score from 1-10 riskLevelstring"green", "yellow", or "red" summarystringAI-generated overview of the document flagsArrayList of flagged clauses with details fullExtractionArray \nullStructured breakdown by section usageobject \nullRate limit and credit info (only for authenticated users)

Flags Array

Each item in flags represents a clause that raised a concern:

FieldTypeDescription -------------------------- categorystringTopic area (Data Privacy, Arbitration, Liability, Content & IP, Billing, Account) severity"low" \"medium" \"high"How significant the concern is textstringExact text from the original document explanationstringPlain-English description of what the clause means riskScorenumberIndividual risk score for this clause (1-10)

Full Extraction Array

Each item in fullExtraction represents a section of the document:

FieldTypeDescription -------------------------- titlestringSection name keyPointsArrayKey points, each with title, detail, quote, and severity

LLM Pipeline

The analysis uses a multi-model pipeline with automatic fallback:

PriorityModelProvider --------------------------- 1google/gemini-2.5-flash-liteOpenRouter 2xiaomi/mimo-v2.5OpenRouter 3google/gemma-4-31b-it:freeOpenRouter 4minimax/minimax-m3OpenRouter 5gemini-2.5-flash-liteGoogle Generative AI (direct) 6Hardcoded fallbackReturns a neutral score with a "review manually" message

If all models fail, the API returns a neutral risk score (5/10) with a single "Unable to analyze" flag.

Code Examples

JavaScript (fetch)

javascript
// First, extract the text

const extractRes = await fetch("https://themys.ca/api/extract", {

method: "POST",

headers: {

"Content-Type": "application/json",

"Authorization": "Bearer YOUR_SESSION_TOKEN",

},

body: JSON.stringify({

url: "https://example.com/terms-of-service",

}),

});

const { text } = await extractRes.json();

// Then, analyze it

const analyzeRes = await fetch("https://themys.ca/api/analyze", {

method: "POST",

headers: {

"Content-Type": "application/json",

"Authorization": "Bearer YOUR_SESSION_TOKEN",

},

body: JSON.stringify({

text,

sourceUrl: "https://example.com/terms-of-service",

domain: "example.com",

}),

});

const result = await analyzeRes.json();

console.log(Risk Score: ${result.riskScore}/10);

console.log(Summary: ${result.summary});

console.log(Flags: ${result.flags.length} clauses flagged);

cURL

bash
# Step 1: Extract text

EXTRACT=$(curl -s -X POST https://themys.ca/api/extract \

-H "Content-Type: application/json" \

-H "Authorization: Bearer YOUR_SESSION_TOKEN" \

-d '{"url": "https://example.com/terms-of-service"}')

TEXT=$(echo $EXTRACT | jq -r '.text')

# Step 2: Analyze text

curl -X POST https://themys.ca/api/analyze \

-H "Content-Type: application/json" \

-H "Authorization: Bearer YOUR_SESSION_TOKEN" \

-d "{\"text\": \"$TEXT\", \"sourceUrl\": \"https://example.com/terms-of-service\", \"domain\": \"example.com\"}"

Error Responses

Missing Input (400)

json
{

"error": "Provide a URL or pasted terms text"

}

Analysis Failed (500)

json
{

"error": "Internal server error"

}

This is rare. Retry after a short wait. If it persists, the LLM providers may be experiencing outages.

Rate Limited (402)

json
{

"error": "Daily scan limit reached",

"upgradeRequired": true,

"tier": "free",

"scansRemaining": 0,

"scansLimit": 5

}

You've exceeded your plan's daily scan limit. Purchase credits or upgrade to continue.

Rate Limits

Each analysis request consumes one scan from your daily limit, or one credit if you've exceeded it.

PlanDaily Scans ------------------ Free5 Base25 Advanced100

Was this page helpful?