POST /api/analyze
Analyze Terms of Service text with AI to get risk scores, flagged clauses, and full extraction.
Endpoint
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:
Authorization: Bearer <your_session_token>
Request Body
{
"text": "Terms of Service\n\n1. Acceptance of Terms\nBy accessing...",
"sourceUrl": "https://example.com/terms-of-service",
"domain": "example.com"
}
textstringtext or urlurlstringtext or url/api/extract internally)sourceUrlstringtext; used as metadata and never fetcheddomainstring"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
{
"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
riskScorenumberriskLevelstring"green", "yellow", or "red"summarystringflagsArrayfullExtractionArray \usageobject \Flags Array
Each item in flags represents a clause that raised a concern:
categorystringseverity"low" \textstringexplanationstringriskScorenumberFull Extraction Array
Each item in fullExtraction represents a section of the document:
titlestringkeyPointsArraytitle, detail, quote, and severityLLM Pipeline
The analysis uses a multi-model pipeline with automatic fallback:
If all models fail, the API returns a neutral risk score (5/10) with a single "Unable to analyze" flag.
Code Examples
JavaScript (fetch)
// 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
# 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)
{
"error": "Provide a URL or pasted terms text"
}
Analysis Failed (500)
{
"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)
{
"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.
Was this page helpful?