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

  1. Go to Settings in the dashboard
  2. Scroll to the API Keys section
  3. 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/reviews

Upload a contract PDF for AI analysis.

Request

Content-Type: multipart/form-data

FieldTypeDescription
fileFile (required)PDF file, max 20MB
contract_typestringOptional. 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/reviews

List your contract reviews.

Query Parameters

limitnumberOptional. 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/:id

Get 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/:id

Permanently 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

CodeDescription
400Bad request — missing file, invalid format, or file too large
401Unauthorized — missing or invalid API key
403Forbidden — feature not available on your plan
404Not found — review does not exist or does not belong to you
429Rate limited — monthly review limit reached
500Server 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.

PlanReviews / monthAPI Access
Free3No
Pro30Yes
TeamUnlimitedYes