API Reference

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.

Base URL: https://ada.fru.ioAPI Key AuthREST / multipart

Quick Start

Remediate a PDF in three steps:

  1. 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. 2

    Send a PDF to the API

    POST your PDF as multipart/form-data with your API key in the X-API-Key header.

  3. 3

    Receive the remediated PDF

    The response body is the remediated PDF file. Response headers include compliance score, issues fixed, and processing metadata.

Quick start examplebash
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.pdf

Authentication

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. 1. Create an account (free, no credit card)
  2. 2. Go to Dashboard → API Keys
  3. 3. Click Create API Key and give it a name
  4. 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
Authentication headerhttp
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.

POST/api/v1/remediate

Content-Type: multipart/form-data

Parameters

ParameterTypeRequiredDescription
fileFileRequiredThe PDF file to remediate. Max 10 MB (free), 50 MB (basic), 100 MB (full AI).
includeAIStringOptionalSet to "true" for full AI remediation (alt text, semantic tagging, contrast). Requires full AI access. Default: "false"
titleStringOptionalCustom 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.

HeaderDescription
X-Remediation-SuccessWhether remediation completed successfully (true/false)
X-Compliance-ScoreOverall accessibility compliance score (0-100)
X-Compliance-PassedWhether the document passes compliance validation (true/false)
X-Issues-Fixed-PDFUANumber of PDF/UA issues fixed
X-Issues-Fixed-WCAGNumber of WCAG issues fixed
X-Issues-Fixed-QualityNumber of quality improvements (alt text, etc.)
X-AI-EnhancedWhether AI features were applied (true/false)
X-Pages-ProcessedTotal pages processed in this request
X-Processing-Time-MsServer-side processing time in milliseconds
X-MCIDs-GeneratedNumber of marked content IDs generated
X-Structure-ElementsNumber of structure tree elements created
X-RateLimit-LimitMaximum requests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetISO 8601 timestamp when the rate limit resets
X-Quota-OveragePresent (true) if request exceeds monthly plan pages

Error Codes

StatusError CodeDescription
400invalid_requestRequest body must be multipart/form-data
400missing_fileNo PDF file provided in the "file" field
400invalid_pdfThe uploaded file is not a valid PDF
401authentication_requiredMissing X-API-Key header
401invalid_api_keyAPI key is invalid, expired, or revoked
403account_inactiveAccount is suspended or deactivated
429rate_limit_exceededToo many requests per minute
429quota_exceededMonthly page limit reached
500remediation_failedInternal error during PDF processing

Rate Limits & Quotas

Rate Limits

Per API key, per minute. Check X-RateLimit-* headers.

All accounts120 req/min

Pricing

Each page of a PDF counts as one page. Pay only for what you process.

Full AI remediation$2/page
SubscriptionsNone — pay as you go

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 remediationbash
# 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

python — requestspython
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

node.js — fetchjavascript
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 — cURLphp
<?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

.NET — HttpClientcsharp
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.

Batch processing — bashbash
#!/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.