Developers

The CheckMyDoc API

Submit contracts. Get back risk scores, plain-English findings, redlines, and a full compliance pass. Available on Pro (rate-limited) and Scale (unlimited).

Quick start

Three calls to get from a file on disk to a finished review.

  1. Generate an API key

    On a Pro or Scale plan, head to Settings → API keys and create one. Keys look like ll_live_… and are shown once at creation.

  2. Initialize the upload

    POST file metadata to /api/upload. You receive a presigned URL — PUT the file bytes directly to it.

    curl -X POST https://checkmydoc.co/api/upload \
      -H "Authorization: Bearer ll_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
      -H "Content-Type: application/json" \
      -d '{
        "filename": "msa-acme.pdf",
        "mimeType": "application/pdf",
        "sizeBytes": 184320,
        "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
      }'
    Response
    {
      "documentId": "f9a3…",
      "uploadUrl": "https://…r2.cloudflarestorage.com/…?X-Amz-Signature=…",
      "method": "PUT",
      "headers": { "Content-Type": "application/pdf" },
      "expiresAt": "2026-05-01T18:30:00Z"
    }

    Compute the SHA-256 client-side. We verify it server-side via Cloudflare R2.

  3. PUT the file to the presigned URL

    curl -X PUT "$UPLOAD_URL" \
      -H "Content-Type: application/pdf" \
      --data-binary @msa-acme.pdf
  4. Mark the upload complete

    curl -X POST https://checkmydoc.co/api/upload/complete \
      -H "Authorization: Bearer ll_live_…" \
      -H "Content-Type: application/json" \
      -d '{ "documentId": "f9a3…" }'
  5. Run the review

    curl -X POST https://checkmydoc.co/api/review/f9a3…/run \
      -H "Authorization: Bearer ll_live_…" \
      -H "Content-Type: application/json" \
      -d '{ "tone": "founder_friendly" }'

    The response contains the review id, classification, risk score, and token usage. Findings, redlines, and the compliance breakdown are persisted server-side — fetch them in step 6.

  6. Fetch the findings

    curl https://checkmydoc.co/api/review/f9a3… \
      -H "Authorization: Bearer ll_live_…"

    Returns the full review payload — findings array, redlines array, compliance object, document metadata, and token / latency stats. The path accepts either the document id or a specific review id.

Authentication

Every API request must include a Bearer token in the Authorization header:

Authorization: Bearer ll_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are scoped to a single team. We validate the team's plan on every request — if the subscription downgrades below Pro, the key stops authenticating immediately. Revoked keys return 401 without delay.

Treat keys like passwords. Store them in your secret manager, not in source. We show the full key once at generation time and only the prefix afterwards.

Endpoints

All endpoints are JSON over HTTPS. UTF-8 throughout. ISO-8601 timestamps in UTC.

POST/api/upload

Initialize an upload — returns a presigned URL.

Request body

{
  "filename": "msa-acme.pdf",        // string, ≤ 255 chars
  "mimeType": "application/pdf",     // pdf | docx | doc | text/plain
  "sizeBytes": 184320,               // 64 ≤ N ≤ 26214400 (25 MB)
  "sha256": "e3b0c44298fc1c149a…",   // 64-char lowercase hex
  "templateId": "vendor_msa"         // optional — see Templates list
}

Response — 200 OK

{
  "documentId": "f9a3a4b6-…",
  "uploadUrl": "https://…r2…?X-Amz-Signature=…",
  "method": "PUT",
  "headers": { "Content-Type": "application/pdf" },
  "expiresAt": "2026-05-01T18:30:00Z"
}
  • PUT the file bytes directly to uploadUrl. The presign expires in 15 minutes.
  • Document quota check happens here, not at /complete.
POST/api/upload/complete

Mark a presigned upload as complete after the PUT succeeds.

Request body

{
  "documentId": "f9a3a4b6-…"  // returned by /api/upload
}

Response — 200 OK

{
  "ok": true,
  "document": {
    "id": "f9a3a4b6-…",
    "status": "uploaded",
    "originalFilename": "msa-acme.pdf",
    "mimeType": "application/pdf",
    "sizeBytes": 184320,
    "templateId": "vendor_msa",
    "createdAt": "2026-05-01T18:15:21Z"
  }
}
  • Idempotent — safe to retry. Already-complete documents return alreadyComplete: true.
  • Verifies the object exists in R2 before flipping status.
POST/api/review/{documentId}/run

Run the review pipeline. Returns when the analysis finishes (≤ 5 min).

Request body

{
  "tone": "founder_friendly"
  // Optional. One of:
  //   "founder_friendly"     (default)
  //   "vendor_pushback"
  //   "enterprise_neutral"
}

Response — 200 OK

{
  "ok": true,
  "reviewId": "1f0e9a…",
  "classification": "msa",
  "riskScore": 47,                 // 0–100, lower = safer
  "tokensIn": 12480,
  "tokensOut": 2104,
  "latencyMs": 18420,
  "pages": 14
}
  • Long-running — up to 5 min. Set your client timeout accordingly.
  • Findings, redlines, and the compliance breakdown are persisted server-side. Fetch them via GET /api/review/{id}.
  • Counts against your monthly document quota. On Pro, docs past the included 75 are billed in arrears at $2 each; Starter is a hard cap.
GET/api/review/{id}

Fetch the latest review for a document. id can be a document id or a review id.

Request body

// No body — GET request.
// Path id accepts either:
//   - documentId   (returns the most recent review for that doc)
//   - reviewId     (returns that specific review)

Response — 200 OK

{
  "review": {
    "id": "1f0e9a…",
    "documentId": "f9a3a4b6-…",
    "status": "complete",
    "classification": "msa",
    "summary": "Vendor MSA with broad indemnity and unlimited liability cap…",
    "riskScore": 47,
    "findings": [
      {
        "clause": "Indemnification",
        "location": "Section 9.2",
        "severity": "high",
        "issue": "Mutual indemnity is missing — only Customer indemnifies.",
        "suggestion": "Make indemnity reciprocal …"
      }
      // …
    ],
    "redlines": [
      {
        "clause": "Limitation of Liability",
        "original": "Provider's total liability shall not exceed $1,000.",
        "suggested": "Provider's total liability shall not exceed fees paid in the prior 12 months."
      }
      // …
    ],
    "compliance": {
      "gdpr": { "status": "missing_dpa", "notes": "…" },
      "ccpa": { "status": "ok" }
      // …
    },
    "modelUsed": "claude-opus-4-7",
    "tokensIn": 12480,
    "tokensOut": 2104,
    "latencyMs": 18420,
    "createdAt": "2026-05-01T18:18:42Z"
  },
  "document": {
    "id": "f9a3a4b6-…",
    "originalFilename": "msa-acme.pdf",
    "mimeType": "application/pdf",
    "sizeBytes": 184320,
    "templateId": "vendor_msa",
    "status": "complete",
    "createdAt": "2026-05-01T18:15:21Z"
  }
}
  • Tenant-scoped: 404 if the id belongs to another team.
  • Soft-deleted documents return 404. Hard purge happens within 30 days per the DPA.
  • Re-running /run on the same document creates a new review row; this endpoint always returns the latest.

Errors

Every error response is JSON with an error string. Some 402s include a reason code so your client can react without parsing prose.

CodeMeaningWhat to do
400Validation failedRead error and fix the offending field.
401Missing / invalid / revoked keyRe-check the Authorization header. Keys belong to a team — keep the right key with the right tenant.
402Quota or billing blockUpgrade plan or wait for the next period. reason is monthly_cap, free_cap_reached, or subscription_inactive.
404Document not found in your teamdocumentId belongs to another team or was deleted.
409Upload not in storage yetThe presigned PUT did not complete. Retry the PUT, then call /complete.
429Rate limitedBack off and retry after the suggested interval. See Rate limits.
500Pipeline errorSurfaced when the AI step fails. Safe to retry — quota is only debited on successful runs.
503Storage / AI not configuredServer-side env issue. Email hello@checkmydoc.co if you see this in production.

Rate limits

Limits are per API key, sliding window:

  • POST /api/upload30 / minute
  • POST /api/review/{id}/run5 / minute
  • GET /api/review/{id}120 / minute

On 429 we return a friendly error like { "error": "Slow down. Try again in 12s." }. Scale customers can negotiate higher ceilings — talk to sales@checkmydoc.co.

Webhooks

Coming soon

Async review.completed webhooks land next quarter, so you can stop polling /api/review/{id}/run for long PDFs. Signed with HMAC-SHA-256 + retry semantics.

Ready to integrate?

Generate a key on Pro — $69 / month, 75 docs included, $2 per top-up doc.