API Documentation
Programmatically upload contracts and retrieve analysis results. Available on Pro and Team plans.
Authentication
All API requests require a Bearer token in the Authorization header. API keys are available to Pro and Team plan users.
How to get your API key
- Go to Settings in the dashboard
- Scroll to the API Keys section
- Click Create and copy the key
The key is only shown once at creation. Store it securely.
Authorization: Bearer cs_live_your_api_key_here
Base URL
https://yourdomain.com/api/v1
Replace yourdomain.com with your deployment URL.
Endpoints
POST
/reviewsUpload a contract PDF for AI analysis.
Request
Content-Type: multipart/form-data
| Field | Type | Description |
|---|---|---|
| file | File (required) | PDF file, max 20MB |
| contract_type | string | Optional. One of: nda, freelance, saas, employment, partnership, lease, other |
Response 201
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"file_name": "contract.pdf",
"created_at": "2026-04-01T12:00:00.000Z"
}GET
/reviewsList your contract reviews.
Query Parameters
| limit | number | Optional. Default 20, max 100 |
Response 200
{
"data": [
{
"id": "550e8400-...",
"file_name": "contract.pdf",
"contract_type": "nda",
"risk_score": 72,
"status": "completed",
"created_at": "2026-04-01T12:00:00.000Z"
}
]
}GET
/reviews/:idGet a single review with full analysis results. Poll this endpoint until status is completed.
Response 200
{
"id": "550e8400-...",
"file_name": "contract.pdf",
"file_size_bytes": 245000,
"page_count": 8,
"contract_type": "freelance",
"risk_score": 72,
"status": "completed",
"summary": "This freelance agreement...",
"risks": [
{
"severity": "high",
"clause_ref": "8.2",
"title": "Unlimited Liability",
"description": "No cap on damages...",
"original_text": "Contractor shall be liable...",
"suggestion": "Contractor liability shall not exceed...",
"market_standard": "Industry standard is 1-2x contract value."
}
],
"missing_clauses": [
{
"clause_name": "Termination for Convenience",
"importance": "required",
"description": "No termination clause found..."
}
],
"metadata": {
"parties": ["Acme Corp", "Jane Smith"],
"effective_date": "2026-01-01",
"term": "12 months",
"governing_law": "State of California",
"payment_terms": "Net 30"
},
"created_at": "2026-04-01T12:00:00.000Z"
}DELETE
/reviews/:idPermanently delete a review.
Response 200
{ "ok": true }Response Types
RiskItem
{
"severity": "high" | "medium" | "low",
"clause_ref": string, // e.g. "8.1", "Section 5"
"title": string,
"description": string,
"original_text": string, // verbatim excerpt from the contract
"suggestion": string | null, // safer alternative (high/medium only)
"market_standard": string | null
}MissingClause
{
"clause_name": string,
"importance": "required" | "recommended" | "optional",
"description": string
}ContractMetadata
{
"parties": string[],
"effective_date": string | null,
"term": string | null,
"governing_law": string | null,
"payment_terms": string | null
}Code Examples
Upload a contract (cURL)
curl -X POST https://yourdomain.com/api/v1/reviews \ -H "Authorization: Bearer cs_live_your_key" \ -F "file=@contract.pdf" \ -F "contract_type=nda"
Poll for results (cURL)
curl https://yourdomain.com/api/v1/reviews/REVIEW_ID \ -H "Authorization: Bearer cs_live_your_key"
Upload + poll (Node.js)
const fs = require("fs");
const API_KEY = "cs_live_your_key";
const BASE = "https://yourdomain.com/api/v1";
// 1. Upload
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("contract.pdf")]), "contract.pdf");
const upload = await fetch(`${BASE}/reviews`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}` },
body: form,
});
const { id } = await upload.json();
// 2. Poll until complete
let review;
do {
await new Promise((r) => setTimeout(r, 3000));
const res = await fetch(`${BASE}/reviews/${id}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
review = await res.json();
} while (review.status === "processing");
console.log("Risk score:", review.risk_score);
console.log("Risks:", review.risks.length);Error Codes
| Code | Description |
|---|---|
| 400 | Bad request — missing file, invalid format, or file too large |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — feature not available on your plan |
| 404 | Not found — review does not exist or does not belong to you |
| 429 | Rate limited — monthly review limit reached |
| 500 | Server error — please retry or contact support |
Error response format
{ "error": "Description of what went wrong" }Rate Limits
API requests count toward your monthly plan limit, shared with the dashboard.
| Plan | Reviews / month | API Access |
|---|---|---|
| Free | 3 | No |
| Pro | 30 | Yes |
| Team | Unlimited | Yes |