API Documentation

Integrate XtraOrdinary Research into your applications with our REST API. Generate visa petition documents, create exhibit packages, and manage cases programmatically.

Base URL: https://www.xtraordinarypetitions.com/api/v1

Overview

The XtraOrdinary Research API allows you to programmatically create and manage immigration visa petition cases. You can generate comprehensive petition documents, create exhibit packages with cover pages and tables of contents, and monitor generation progress in real-time.

Create Cases

Start new petition cases with beneficiary information

Generate Documents

8 comprehensive petition documents auto-generated

Exhibit Packages

PDF packages with cover pages and TOC

Authentication

All API requests (except health check) require authentication using an API key. Include your key in the Authorization header.

Authorization: Bearer xr_live_your_api_key_here

Getting an API Key

  1. Sign in to your account
  2. Go to Settings > API Keys
  3. Click "Create API Key" and select permissions
  4. Copy your key immediately - it will only be shown once

Scopes

readView cases, documents, and progress
writeCreate and modify cases
generateStart petition and exhibit generation

Rate Limits

API requests are rate limited on a per-key basis. The default limit is 100 requests per minute. Rate limit information is included in response headers.

HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp when the window resets

If you exceed the rate limit, you will receive a 429 Too Many Requests response. Wait until the reset time before making additional requests.

Endpoints

Error Codes

StatusMeaningDescription
200OKRequest succeeded
201CreatedResource created successfully
202AcceptedGeneration started (async processing)
400Bad RequestInvalid request body or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key lacks required scope
404Not FoundResource does not exist or does not belong to you
409ConflictGeneration already in progress
429Too Many RequestsRate limit exceeded
500Server ErrorInternal server error

Error Response Format

{
  "error": "Human-readable error message",
  "details": {  // Optional - validation errors
    "fieldName": ["Error description"]
  }
}

Code Examples

JavaScript / TypeScript

const API_KEY = 'xr_live_your_api_key';
const BASE = 'https://www.xtraordinarypetitions.com/api/v1';

// List cases
const cases = await fetch(`${BASE}/cases`, {
  headers: { 'Authorization': `Bearer ${API_KEY}` }
}).then(r => r.json());

// Create a case
const newCase = await fetch(`${BASE}/cases`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    beneficiaryName: 'John Doe',
    visaType: 'O-1A',
    fieldOfWork: 'Machine Learning',
  }),
}).then(r => r.json());

const caseId = newCase.data.case_id;

// Start generation
await fetch(`${BASE}/cases/${caseId}/generate`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    beneficiaryInfo: {
      fullName: 'John Doe',
      visaType: 'O-1A',
      fieldOfWork: 'Machine Learning',
    },
    urls: ['https://scholar.google.com/citations?user=...'],
  }),
});

// Poll for progress
const poll = setInterval(async () => {
  const progress = await fetch(
    `${BASE}/cases/${caseId}/progress`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  ).then(r => r.json());

  console.log(`Progress: ${progress.data.petition.progress}%`);

  if (progress.data.petition.status === 'completed') {
    clearInterval(poll);
    console.log('Generation complete!');
  }
}, 5000);

Python

import requests
import time

API_KEY = "xr_live_your_api_key"
BASE = "https://www.xtraordinarypetitions.com/api/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}

# List cases
cases = requests.get(f"{BASE}/cases", headers=headers).json()
print(f"Found {cases['pagination']['total']} cases")

# Create a case
new_case = requests.post(f"{BASE}/cases", headers=headers, json={
    "beneficiaryName": "John Doe",
    "visaType": "O-1A",
    "fieldOfWork": "Machine Learning",
}).json()

case_id = new_case["data"]["case_id"]

# Start generation
requests.post(f"{BASE}/cases/{case_id}/generate", headers=headers, json={
    "beneficiaryInfo": {
        "fullName": "John Doe",
        "visaType": "O-1A",
        "fieldOfWork": "Machine Learning",
    },
    "urls": ["https://scholar.google.com/citations?user=..."],
})

# Poll for progress
while True:
    progress = requests.get(
        f"{BASE}/cases/{case_id}/progress",
        headers=headers
    ).json()

    pct = progress["data"]["petition"]["progress"]
    status = progress["data"]["petition"]["status"]
    print(f"Progress: {pct}% - Status: {status}")

    if status == "completed":
        print("Generation complete!")
        break

    time.sleep(5)

# Get documents
docs = requests.get(
    f"{BASE}/cases/{case_id}/documents",
    headers=headers
).json()

for doc in docs["data"]:
    print(f"  Document {doc['documentNumber']}: {doc['documentName']}")

cURL

# Health check (no auth required)
curl https://www.xtraordinarypetitions.com/api/v1/health

# List your cases
curl -H "Authorization: Bearer xr_live_your_api_key" \
  "https://www.xtraordinarypetitions.com/api/v1/cases"

# Get case progress
curl -H "Authorization: Bearer xr_live_your_api_key" \
  "https://www.xtraordinarypetitions.com/api/v1/cases/ABCD1234EFGH/progress"

# Download a document as markdown
curl -H "Authorization: Bearer xr_live_your_api_key" \
  "https://www.xtraordinarypetitions.com/api/v1/cases/ABCD1234EFGH/documents/1?format=markdown" \
  -o document.md

Ready to Get Started?

Create an account and get your API key to start integrating with XtraOrdinary Research.