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/v1Overview
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_hereGetting an API Key
- Sign in to your account
- Go to Settings > API Keys
- Click "Create API Key" and select permissions
- Copy your key immediately - it will only be shown once
Scopes
readView cases, documents, and progresswriteCreate and modify casesgenerateStart petition and exhibit generationRate 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.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Remaining requests in current window |
X-RateLimit-Reset | Unix 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
| Status | Meaning | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
202 | Accepted | Generation started (async processing) |
400 | Bad Request | Invalid request body or parameters |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | API key lacks required scope |
404 | Not Found | Resource does not exist or does not belong to you |
409 | Conflict | Generation already in progress |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Internal 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.mdReady to Get Started?
Create an account and get your API key to start integrating with XtraOrdinary Research.