TrueAccessibility

API Documentation

Everything you need to integrate TrueAccessibility into your workflow.

Quick Start

Upload and remediate a PDF in three API calls.

1. Get an API key

Go to Settings → API Keys and create a new key with upload and documents:read scopes.

2. Initialize an upload

curl -X POST https://api.trueaccessibility.com/api/upload/init \
  -H "X-API-Key: ta_sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "report.pdf",
    "fileSize": 1024000,
    "contentType": "application/pdf"
  }'

This returns a uploadUrl (presigned S3 URL) and documentId. Upload your file to the presigned URL with a PUT request.

3. Complete the upload

curl -X POST https://api.trueaccessibility.com/api/upload/complete \
  -H "X-API-Key: ta_sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"documentId": "DOCUMENT_ID"}'

Processing starts automatically. Poll GET /api/documents/DOCUMENT_ID to check status, or set up a webhook.

4. Download the accessible PDF

curl https://api.trueaccessibility.com/api/documents/DOCUMENT_ID/download \
  -H "X-API-Key: ta_sk_your_api_key_here"

Returns a presigned URL to download the WCAG 2.2 / PDF/UA-1 compliant PDF.

Authentication

TrueAccessibility supports two authentication methods:

API Keys (recommended for integrations)

Create API keys in Settings with specific scopes. Pass them in the X-API-Key header:

X-API-Key: ta_sk_your_api_key_here

JavaScript Example

const response = await fetch('https://api.trueaccessibility.com/api/documents', {
  headers: {
    'X-API-Key': 'ta_sk_your_api_key_here',
    'Content-Type': 'application/json',
  },
});
const data = await response.json();

Available Scopes

  • documents:read -- Read document data and download files
  • documents:write -- Create and modify documents
  • documents:remediate -- Trigger remediation processing
  • upload -- Upload new PDF files
  • projects:read -- Read project data
  • projects:write -- Create and modify projects
  • analytics:read -- Access analytics and reports
  • webhooks:manage -- Create, update, and delete webhooks

JWT Tokens (for browser sessions)

Obtained via POST /api/auth/login. Tokens expire after 24 hours. Used automatically by the web dashboard.

API Endpoints

All endpoints are prefixed with https://api.trueaccessibility.com/api

POST
/api/v1/documents/upload

Upload a PDF

Initialize a document upload. Returns a presigned S3 URL for direct upload and a documentId.

Required scope: upload

GET
/api/v1/documents/:id

Get document status

Retrieve the current status, metadata, and progress of a document.

Required scope: documents:read

GET
/api/v1/documents/:id/download

Download remediated PDF

Get a presigned download URL for the WCAG 2.2 / PDF/UA-1 compliant output.

Required scope: documents:read

POST
/api/v1/documents/:id/remediate

Trigger remediation

Re-trigger remediation on a failed or completed document with new settings.

Required scope: documents:remediate

GET
/api/v1/documents

List documents

List all documents in your organization with pagination and status filtering.

Required scope: documents:read

POST
/api/v1/webhooks

Register webhook

Register a webhook endpoint to receive real-time event notifications.

Required scope: webhooks:manage

Code Examples

cURL -- Upload and remediate a document

# 1. Initialize upload
INIT=$(curl -s -X POST https://api.trueaccessibility.com/api/upload/init \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename":"report.pdf","fileSize":'$(stat -f%z report.pdf)',"contentType":"application/pdf"}')

UPLOAD_URL=$(echo $INIT | jq -r '.uploadUrl')
DOC_ID=$(echo $INIT | jq -r '.documentId')

# 2. Upload the file to S3
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  --data-binary @report.pdf

# 3. Signal upload complete (triggers processing)
curl -X POST https://api.trueaccessibility.com/api/upload/complete \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"documentId":"'$DOC_ID'"}'

# 4. Poll status until completed
curl -s https://api.trueaccessibility.com/api/documents/$DOC_ID \
  -H "X-API-Key: $API_KEY" | jq '.status'

# 5. Download the remediated file
curl -s https://api.trueaccessibility.com/api/documents/$DOC_ID/download \
  -H "X-API-Key: $API_KEY" | jq -r '.url'

JavaScript / Node.js

const API_KEY = 'ta_sk_your_api_key_here';
const BASE_URL = 'https://api.trueaccessibility.com/api';

const headers = {
  'X-API-Key': API_KEY,
  'Content-Type': 'application/json',
};

// 1. Initialize upload
const initRes = await fetch(`${BASE_URL}/upload/init`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    filename: 'report.pdf',
    fileSize: fileBuffer.byteLength,
    contentType: 'application/pdf',
  }),
});
const { documentId, uploadUrl } = await initRes.json();

// 2. Upload file to presigned URL
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/pdf' },
  body: fileBuffer,
});

// 3. Signal upload complete
await fetch(`${BASE_URL}/upload/complete`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ documentId }),
});

// 4. Poll until complete
let status = 'detecting';
while (!['completed', 'failed'].includes(status)) {
  await new Promise(r => setTimeout(r, 5000));
  const res = await fetch(`${BASE_URL}/documents/${documentId}`, { headers });
  const doc = await res.json();
  status = doc.status;
  console.log(`Status: ${status} (${doc.progress || 0}%)`);
}

// 5. Download result
const dlRes = await fetch(`${BASE_URL}/documents/${documentId}/download`, { headers });
const { url } = await dlRes.json();
console.log('Download URL:', url);

Register a webhook

curl -X POST https://api.trueaccessibility.com/api/webhooks \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhook",
    "events": ["document.completed", "document.failed"]
  }'

Rate Limits

Rate limits are applied per API key and vary by subscription tier. Exceeding the rate limit returns HTTP 429.

TierRate LimitConcurrent JobsProcessing Priority
Free Trial100/hour3Basic
Starter1,000/hour10Standard
Professional5,000/hour20High
EnterpriseUnlimited50Highest

Webhooks

Receive real-time HTTP POST notifications when events occur.

Available events

  • document.uploaded -- A new document has been uploaded
  • document.processing -- Document processing has started
  • document.completed -- Processing finished successfully
  • document.failed -- Processing failed with an error
  • review.needed -- Document requires manual review
  • review.submitted -- An OCR review task was submitted

Payload format

{
  "event": "document.completed",
  "data": {
    "documentId": "550e8400-e29b-41d4-a716-446655440000",
    "orgId": "org_abc123",
    "status": "completed",
    "filename": "report.pdf",
    "pageCount": 42,
    "downloadUrl": "https://..."
  },
  "timestamp": "2026-04-10T12:00:00.000Z",
  "webhookId": "wh_xyz789"
}

Signature verification

Each webhook delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the payload using your webhook secret. Verify this to ensure the payload is authentic.

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your Express handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;
  switch (event) {
    case 'document.completed':
      console.log('Document ready:', data.documentId);
      break;
    case 'document.failed':
      console.error('Processing failed:', data.documentId);
      break;
  }

  res.status(200).send('OK');
});

Retry policy

Failed webhook deliveries (non-2xx response or timeout) are retried up to 3 times with exponential backoff: 2 seconds, then 4 seconds. Delivery attempts and responses are logged and visible in the webhook settings panel.