ADA.fru.io API
Integrate PDF accessibility remediation into your application with a single API call. Upload a PDF, get back a fully compliant document.
https://ada.fru.ioAPI Key AuthREST / multipartQuick Start
Remediate a PDF in three steps:
- 1
Create an account and get your API key
Sign up free, then go to Dashboard → API Keys to generate a key. Add a payment method to start — remediation is billed at $2 per page.
- 2
Send a PDF to the API
POST your PDF as
multipart/form-datawith your API key in theX-API-Keyheader. - 3
Receive the remediated PDF
The response body is the remediated PDF file. Response headers include compliance score, issues fixed, and processing metadata.
curl -X POST https://ada.fru.io/api/v1/remediate \
-H "X-API-Key: ak_your_api_key_here" \
-F "[email protected]" \
-F "includeAI=false" \
-o remediated-document.pdfAuthentication
All API requests require an API key passed in the X-API-Key header. Keys are scoped to your account and can be created, rotated, and revoked from the dashboard.
Getting your API key
- 1. Create an account (free, no credit card)
- 2. Go to Dashboard → API Keys
- 3. Click Create API Key and give it a name
- 4. Copy the key immediately — it is shown only once
Security best practices
- Store API keys in environment variables, never in code
- Use separate keys for development and production
- Rotate keys periodically and revoke unused ones
- Each account can have up to 5 active keys
POST /api/v1/remediate HTTP/1.1
Host: ada.fru.io
X-API-Key: ak_a1b2c3d4e5f6...
Content-Type: multipart/form-data; boundary=---POST /api/v1/remediate
Upload a PDF document and receive a fully remediated, accessible version. The API performs structural fixes, content tagging, and optionally AI-powered enhancements in a single synchronous request.
/api/v1/remediateContent-Type: multipart/form-data
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| file | File | Required | The PDF file to remediate. Max 10 MB (free), 50 MB (basic), 100 MB (full AI). |
| includeAI | String | Optional | Set to "true" for full AI remediation (alt text, semantic tagging, contrast). Requires full AI access. Default: "false" |
| title | String | Optional | Custom document title for the PDF metadata. Defaults to the uploaded filename (without .pdf extension). |
Response
On success (HTTP 200), the response body is the remediated PDF binary. Metadata about the remediation is returned in response headers.
Success (200)
Body: Remediated PDF binary
Content-Type: application/pdf
Content-Disposition: attachment; filename="remediated-document.pdf"
Error (4xx / 5xx)
{
"error": "error_code",
"message": "Human-readable description of the error"
}Response Headers
Every successful response includes detailed headers about the remediation process. Use these to build dashboards, reports, or quality gates in your CI/CD pipeline.
| Header | Description |
|---|---|
| X-Remediation-Success | Whether remediation completed successfully (true/false) |
| X-Compliance-Score | Overall accessibility compliance score (0-100) |
| X-Compliance-Passed | Whether the document passes compliance validation (true/false) |
| X-Issues-Fixed-PDFUA | Number of PDF/UA issues fixed |
| X-Issues-Fixed-WCAG | Number of WCAG issues fixed |
| X-Issues-Fixed-Quality | Number of quality improvements (alt text, etc.) |
| X-AI-Enhanced | Whether AI features were applied (true/false) |
| X-Pages-Processed | Total pages processed in this request |
| X-Processing-Time-Ms | Server-side processing time in milliseconds |
| X-MCIDs-Generated | Number of marked content IDs generated |
| X-Structure-Elements | Number of structure tree elements created |
| X-RateLimit-Limit | Maximum requests allowed per minute |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | ISO 8601 timestamp when the rate limit resets |
| X-Quota-Overage | Present (true) if request exceeds monthly plan pages |
Error Codes
| Status | Error Code | Description |
|---|---|---|
| 400 | invalid_request | Request body must be multipart/form-data |
| 400 | missing_file | No PDF file provided in the "file" field |
| 400 | invalid_pdf | The uploaded file is not a valid PDF |
| 401 | authentication_required | Missing X-API-Key header |
| 401 | invalid_api_key | API key is invalid, expired, or revoked |
| 403 | account_inactive | Account is suspended or deactivated |
| 429 | rate_limit_exceeded | Too many requests per minute |
| 429 | quota_exceeded | Monthly page limit reached |
| 500 | remediation_failed | Internal error during PDF processing |
Rate Limits & Quotas
Rate Limits
Per API key, per minute. Check X-RateLimit-* headers.
Pricing
Each page of a PDF counts as one page. Pay only for what you process.
Payment required: add a payment method before your first remediation. Requests without a card on file return 402 payment_required. Pages are billed at $2 each and invoiced automatically.
Code Examples
cURL
# Basic structural remediation
curl -X POST https://ada.fru.io/api/v1/remediate \
-H "X-API-Key: $ADA_API_KEY" \
-F "[email protected]" \
-o remediated-report.pdf
# Full AI remediation
curl -X POST https://ada.fru.io/api/v1/remediate \
-H "X-API-Key: $ADA_API_KEY" \
-F "[email protected]" \
-F "includeAI=true" \
-F "title=Annual Report 2025" \
-o remediated-report.pdf
# Check compliance score from response headers
curl -X POST https://ada.fru.io/api/v1/remediate \
-H "X-API-Key: $ADA_API_KEY" \
-F "[email protected]" \
-o remediated-report.pdf \
-D - 2>/dev/null | grep "X-Compliance-Score"Python
import requests
import os
API_KEY = os.environ["ADA_API_KEY"]
BASE_URL = "https://ada.fru.io"
def remediate_pdf(input_path, output_path, include_ai=False):
"""Remediate a PDF and save the accessible version."""
with open(input_path, "rb") as f:
response = requests.post(
f"{BASE_URL}/api/v1/remediate",
headers={"X-API-Key": API_KEY},
files={"file": (os.path.basename(input_path), f, "application/pdf")},
data={"includeAI": "true" if include_ai else "false"},
)
response.raise_for_status()
with open(output_path, "wb") as out:
out.write(response.content)
# Access remediation metadata from headers
score = response.headers.get("X-Compliance-Score")
issues = response.headers.get("X-Issues-Fixed-PDFUA")
pages = response.headers.get("X-Pages-Processed")
print(f"Score: {score}, Issues fixed: {issues}, Pages: {pages}")
return response.headers
# Usage
remediate_pdf("report.pdf", "report-accessible.pdf")
remediate_pdf("brochure.pdf", "brochure-accessible.pdf", include_ai=True)Node.js
import fs from 'fs';
import path from 'path';
const API_KEY = process.env.ADA_API_KEY;
const BASE_URL = 'https://ada.fru.io';
async function remediatePdf(inputPath, outputPath, includeAI = false) {
const formData = new FormData();
const file = new Blob([fs.readFileSync(inputPath)], {
type: 'application/pdf',
});
formData.append('file', file, path.basename(inputPath));
formData.append('includeAI', String(includeAI));
const response = await fetch(`${BASE_URL}/api/v1/remediate`, {
method: 'POST',
headers: { 'X-API-Key': API_KEY },
body: formData,
});
if (!response.ok) {
const error = await response.json();
throw new Error(`${error.error}: ${error.message}`);
}
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync(outputPath, buffer);
console.log('Score:', response.headers.get('X-Compliance-Score'));
console.log('Issues fixed:', response.headers.get('X-Issues-Fixed-PDFUA'));
return Object.fromEntries(response.headers);
}
// Usage
await remediatePdf('report.pdf', 'report-accessible.pdf');PHP
<?php
$apiKey = getenv('ADA_API_KEY');
$baseUrl = 'https://ada.fru.io';
function remediatePdf($inputPath, $outputPath, $includeAI = false) {
global $apiKey, $baseUrl;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "$baseUrl/api/v1/remediate",
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => ["X-API-Key: $apiKey"],
CURLOPT_POSTFIELDS => [
'file' => new CURLFile($inputPath, 'application/pdf'),
'includeAI' => $includeAI ? 'true' : 'false',
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("API error: HTTP $httpCode");
}
$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
file_put_contents($outputPath, $body);
// Parse compliance score from headers
preg_match('/X-Compliance-Score: (\S+)/', $headers, $matches);
echo "Compliance Score: " . ($matches[1] ?? 'N/A') . "\n";
}
// Usage
remediatePdf('report.pdf', 'report-accessible.pdf');
remediatePdf('brochure.pdf', 'brochure-accessible.pdf', true);C# / .NET
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("ADA_API_KEY"));
using var content = new MultipartFormDataContent();
using var fileStream = File.OpenRead("report.pdf");
content.Add(new StreamContent(fileStream), "file", "report.pdf");
content.Add(new StringContent("false"), "includeAI");
var response = await client.PostAsync(
"https://ada.fru.io/api/v1/remediate", content);
response.EnsureSuccessStatusCode();
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("report-accessible.pdf", pdfBytes);
var score = response.Headers.GetValues("X-Compliance-Score").First();
Console.WriteLine($"Compliance Score: {score}");Batch Processing
Process multiple PDFs by iterating over a directory. Use concurrent requests (up to your rate limit) for throughput.
#!/bin/bash
# Remediate all PDFs in a directory
INPUT_DIR="./pdfs"
OUTPUT_DIR="./accessible"
mkdir -p "$OUTPUT_DIR"
for pdf in "$INPUT_DIR"/*.pdf; do
filename=$(basename "$pdf")
echo "Processing: $filename"
curl -s -X POST https://ada.fru.io/api/v1/remediate \
-H "X-API-Key: $ADA_API_KEY" \
-F "file=@$pdf" \
-o "$OUTPUT_DIR/remediated-$filename" \
-w " Score: %{header.X-Compliance-Score} Time: %{time_total}s\n"
done
echo "Done. Remediated $(ls $OUTPUT_DIR | wc -l) files."Webhooks
Coming soon. Webhook notifications for remediation completion, quota warnings, and billing events will be available for paid accounts. Subscribe to events via the dashboard settings.
SDKs & Libraries
The API uses standard REST conventions with multipart file upload. No SDK is required — use any HTTP client in any language.
Python
pip install requests
requests library
Node.js
Built-in fetch (Node 18+)
No dependencies needed
PHP
Built-in cURL
No dependencies needed
.NET
System.Net.Http
Built-in HttpClient
Ready to integrate?
Create a free account and generate your API key to start remediating PDFs.