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
| Environment | Base URL |
|---|---|
| Production | https://your-domain.com/api/public/v1 |
| Development | http://localhost:3000/api/public/v1 |
| OpenAPI Spec | GET /api/public/v1/openapi |
Interactive Endpoint Reference
Service Health
Verify public API availability and release version without authentication.
Account Details
Verify your API key, ownership, and organization metadata.
Submit Contract
Upload a document file or register a public URL for AI risk analysis.
Processing Status
Poll real-time background analysis progress and step indicators.
Risk Analysis
Fetch extracted contract clauses, identified risks, and recommended fixes.
List Documents
Retrieve paginated lists of analyzed contracts for your account.
Authentication & API Keys
All authenticated requests must include your API key as a Bearer token in the Authorization header.
Generating an API Key
- Log in to the OutRiskAI Dashboard and navigate to your Profile page (
/profile). - Scroll to the API Credentials section.
- Click Generate New Secret to issue a key.
- Copy the secret key (
ork_live_...) immediately. The secret token is shown only once at creation. - Store the key in your secure environment variable store or secret manager.
Authorization: Bearer ork_live_your_secret_keyKeep 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
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token format: Bearer ork_live_<your_secret_key> |
Idempotency-Key | For POST | Unique string (max 255 chars) preventing duplicate submissions. |
Content-Type | Conditional | application/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). Unencryptedhttp://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 Acceptedresponse with anIdempotent-Replayed: trueheader. - 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
409witherror.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)| Status | Description |
|---|---|
queued | Job is waiting in queue or waiting between automatic retries. |
processing | AI risk extraction pipeline is actively processing the contract. |
completed | Contract analysis is complete. Detailed results available at /analysis. |
failed | Processing 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 Status | Error Code | Description |
|---|---|---|
400 | validation_error | Request body, query parameters, or file format failed validation. |
401 | unauthorized | API key is missing, malformed, expired, or revoked. |
403 | forbidden | API key lacks required scope (documents:read or documents:write). |
404 | not_found | Resource does not exist or belongs to another organization. |
409 | conflict | Idempotency key payload mismatch or duplicate request in progress. |
413 | payload_too_large | Uploaded document or request payload exceeds 20 MB limit. |
415 | unsupported_media_type | Content type or file format is unsupported. |
429 | rate_limited | API key exceeded request rate limit window. |
500 | internal_error | Server 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 at1(default:1).limit— Items per page, max100(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 aRetry-Afterheader 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;
}