DocumentationAPI Reference
Api

Public API

Complete REST API guide for integrating OutRiskAI contract analysis into your workflows

The OutRiskAI Public API allows external software systems, CRMs, document management platforms, and custom backend applications to programmatically submit contracts for risk analysis, poll background processing jobs, and retrieve structured legal risk assessments.

Explore our interactive API Reference to test live endpoints, view automatically updated request and response schemas, and try out requests in the interactive playground.

Base URL and OpenAPI Spec

EnvironmentBase URL
Productionhttps://your-domain.com/api/public/v1
Developmenthttp://localhost:3000/api/public/v1
OpenAPI SpecGET /api/public/v1/openapi

Interactive Endpoint Reference

Authentication & API Keys

All authenticated requests must include your API key as a Bearer token in the Authorization header.

Generating an API Key

  1. Log in to the OutRiskAI Dashboard and navigate to your Profile page (/profile).
  2. Scroll to the API Credentials section.
  3. Click Generate New Secret to issue a key.
  4. Copy the secret key (ork_live_...) immediately. The secret token is shown only once at creation.
  5. Store the key in your secure environment variable store or secret manager.
Authorization: Bearer ork_live_your_secret_key

Keep your API keys confidential. Do not commit keys to source control or embed them in client-side code. Revoke keys immediately from your Profile if compromised.

API Key Scopes

Each API key carries permissions scoped to document operations:

  • documents:read — Allows listing documents, viewing metadata, polling status, and reading risk analysis results.
  • documents:write — Allows submitting new contract documents (URL or file) and deleting documents.

Request Headers

HeaderRequiredDescription
AuthorizationYesBearer token format: Bearer ork_live_<your_secret_key>
Idempotency-KeyFor POSTUnique string (max 255 chars) preventing duplicate submissions.
Content-TypeConditionalapplication/json for URL registration; multipart/form-data for file uploads.

Submitting Documents for Analysis

Contracts can be submitted via a public HTTPS URL or directly as a multipart file upload (POST /documents).

Method 1: Public Document URL (application/json)

Submit contracts hosted on accessible web storage (e.g. S3, Cloud Storage). OutRiskAI fetches the document immediately upon submission and creates its own copy.

curl -s -X POST http://localhost:3000/api/public/v1/documents \
  -H "Authorization: Bearer ork_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: upload-contract-101" \
  -d '{
    "document_url": "https://example.com/contracts/vendor-agreement.pdf"
  }'

Document URL Requirements

  • Scheme: https:// only (default port 443). Unencrypted http:// is strictly rejected.
  • Host Validation: Must resolve to a valid public IP address. Private (10.x.x.x, 192.168.x.x), loopback (127.0.0.1), link-local, and metadata services are blocked.
  • Redirects: Follows up to 3 redirects, re-verifying host safety on each hop.
  • File Types: PDF, PNG, or JPEG (verified by file magic byte inspection, not file extension).
  • Max File Size: 20 MB.

Method 2: Direct File Upload (multipart/form-data)

Upload contract files directly from your system or server:

curl -s -X POST http://localhost:3000/api/public/v1/documents \
  -H "Authorization: Bearer ork_live_your_secret_key" \
  -H "Idempotency-Key: upload-contract-102" \
  -F "file=@./master-services-agreement.pdf"

Idempotency & Safe Retries

All POST /documents requests require a unique Idempotency-Key header (up to 255 characters).

  • Replaying Requests: Retrying a request with the exact same key and payload returns the original 202 Accepted response with an Idempotent-Replayed: true header.
  • Payload Conflict: Submitting the same key with a different request payload returns HTTP 409 Conflict.
  • Concurrent In-Flight Requests: If a second request arrives while the original is still processing, it returns HTTP 409 with error.details.retryable: true.
  • Failed Requests: Submissions that fail validation or encounter transient issues do not consume the key, allowing retry with the same key.

Background Processing Lifecycle

When a contract is submitted, OutRiskAI returns an immediate 202 Accepted with a document ID and background job_id. Analysis runs asynchronously.

 [ queued ] ──> [ processing ] ──> [ completed ] ──> Analysis Ready
                      │
                      └──> [ failed ] (after 3 automatic retries)
StatusDescription
queuedJob is waiting in queue or waiting between automatic retries.
processingAI risk extraction pipeline is actively processing the contract.
completedContract analysis is complete. Detailed results available at /analysis.
failedProcessing exhausted 3 retry attempts. error_message provides details.

Polling Processing Status

Poll GET /documents/{documentId}/status until status changes to completed:

curl -s http://localhost:3000/api/public/v1/documents/doc_12345/status \
  -H "Authorization: Bearer ork_live_your_secret_key"

Sample Response:

{
  "success": true,
  "data": {
    "processing": {
      "job_id": "job_98765",
      "status": "processing",
      "current_step": 2,
      "attempts": 1,
      "error_message": null,
      "updated_at": "2026-10-19T14:30:00Z"
    }
  },
  "error": null
}

Retrieving Risk Analysis Results

Once status reaches completed, call GET /documents/{documentId}/analysis to receive the full structured risk analysis.

curl -s http://localhost:3000/api/public/v1/documents/doc_12345/analysis \
  -H "Authorization: Bearer ork_live_your_secret_key"

Sample Response:

{
  "success": true,
  "data": {
    "analysis": {
      "document_id": "doc_12345",
      "summary": "Master Services Agreement with standard payment terms and unilateral termination clause.",
      "risk_count": 2,
      "risks": [
        {
          "id": "risk_01",
          "risk": {
            "title": "Unilateral Termination without Cause",
            "text": "Client may terminate this Agreement at any time without cause upon 7 days notice.",
            "description": "Short termination window presents operational risk for resource planning.",
            "example": "Supplier invests capital but contract is cancelled within 7 days."
          },
          "solutions": [
            {
              "id": "sol_01",
              "solution": "Require a minimum 30-day notice period for termination without cause."
            }
          ],
          "created_at": "2026-10-19T14:32:00Z"
        }
      ]
    }
  },
  "error": null
}

Standard Response Envelope & Errors

All Public API endpoints return a standardized JSON envelope.

Successful Response Format

{
  "success": true,
  "data": { ... },
  "error": null,
  "meta": { ... }
}

Error Response Format

{
  "success": false,
  "data": null,
  "error": {
    "code": "validation_error",
    "message": "Invalid file format. Only PDF, PNG, or JPEG files are allowed.",
    "details": {}
  }
}

Error Codes Table

HTTP StatusError CodeDescription
400validation_errorRequest body, query parameters, or file format failed validation.
401unauthorizedAPI key is missing, malformed, expired, or revoked.
403forbiddenAPI key lacks required scope (documents:read or documents:write).
404not_foundResource does not exist or belongs to another organization.
409conflictIdempotency key payload mismatch or duplicate request in progress.
413payload_too_largeUploaded document or request payload exceeds 20 MB limit.
415unsupported_media_typeContent type or file format is unsupported.
429rate_limitedAPI key exceeded request rate limit window.
500internal_errorServer error encountered. Safe to retry after delay.

Pagination & Rate Limits

Pagination

List endpoints (GET /documents) support 1-based page pagination:

curl -s "http://localhost:3000/api/public/v1/documents?page=1&limit=20" \
  -H "Authorization: Bearer ork_live_your_secret_key"
  • page — Page index, starting at 1 (default: 1).
  • limit — Items per page, max 100 (default: 20).
  • Pagination details are returned in meta.pagination (page, limit, total).

Rate Limits

  • Quota: 100 requests per 15-minute window per API key.
  • Headers Returned:
    • X-RateLimit-Limit: Maximum requests permitted per window.
    • X-RateLimit-Remaining: Remaining requests in current window.
    • X-RateLimit-Reset: Unix timestamp when quota resets.
  • When rate limited (429), the response includes a Retry-After header indicating seconds to wait.

Complete Integration Flow Example

Below is a complete implementation pattern in JavaScript (Node.js Fetch) showing document submission, polling, and risk retrieval:

const API_KEY = process.env.OUTRISK_API_KEY;
const BASE_URL = 'http://localhost:3000/api/public/v1';

async function analyzeContract(documentUrl) {
  // 1. Submit Contract
  const submitRes = await fetch(`${BASE_URL}/documents`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': `upload-${Date.now()}`
    },
    body: JSON.stringify({ document_url: documentUrl })
  });
  
  const submitData = await submitRes.json();
  if (!submitData.success) throw new Error(submitData.error.message);

  const documentId = submitData.data.document.id;
  console.log(`Document submitted successfully. ID: ${documentId}`);

  // 2. Poll Processing Status
  let status = 'queued';
  while (status === 'queued' || status === 'processing') {
    await new Promise(r => setTimeout(r, 3000)); // wait 3 seconds
    
    const statusRes = await fetch(`${BASE_URL}/documents/${documentId}/status`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    });
    const statusData = await statusRes.json();
    status = statusData.data.processing.status;
    console.log(`Current status: ${status}`);
    
    if (status === 'failed') {
      throw new Error(`Analysis failed: ${statusData.data.processing.error_message}`);
    }
  }

  // 3. Retrieve Analysis
  const analysisRes = await fetch(`${BASE_URL}/documents/${documentId}/analysis`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  });
  const analysisData = await analysisRes.json();
  
  console.log('Risk Summary:', analysisData.data.analysis.summary);
  console.log('Identified Risks:', analysisData.data.analysis.risks);
  return analysisData.data.analysis;
}

On this page