Skip to main content

Overview

UX, IA, A11y, Conversion

VertaaUX gives you programmatic audits across usability, information architecture, accessibility, and conversion signals. The API is fully asynchronous: start an audit, receive a job_id, then poll or subscribe to a webhook for completion. All examples below use the public base URL https://vertaaux.ai/v1.

What you get

  • Scores per dimension (usability, clarity, IA, a11y, performance).
  • Issue list with severity, selector, and recommendations.
  • Heatmap prediction and optional HTML snapshot (if enabled).

Typical flow

  1. Send POST /audit with your target URL.
  2. Poll GET /audit/{job_id} until completed.
  3. Store scores/issues in your system or wait for webhook delivery.

Authentication

Authenticate every request with an API key using the X-API-Key header. Keep the key in server-side environments or CI secrets; do not expose it to browsers or client-side code.

Development Testing

For development and testing, create test users with different tier levels. See docs/TEST-USERS.md for test data setup.

Test API keys in a controlled environment before using in production. All audit data is persistent - use test organizations for development.

Get your API key

Create and manage your API keys in the Dashboard → API Keys section. You'll need to be signed in to access this page.

Header format

X-API-Key: your_api_key_here

Requests without a valid key return 401 Unauthorized.

SDKs & Clients

Official SDK scaffolds are available for JS/TS and Python. They include retries, idempotency helpers, webhook verification, and typed responses. Base URL defaults to production; override for staging/test mode.

Copy-paste starter (JS/TS)

import { createVertaauxClient } from "@vertaaux/sdk-js";
const client = createVertaauxClient({ apiKey: "your_api_key_here" });
const audit = await client.createAudit({ url: "https://example.com", mode: "basic" });
const status = await client.getAudit(audit.job_id);

JS/TS

pnpm add ./sdk/js
import { createVertaauxClient, generateIdempotencyKey } from "@vertaaux/sdk-js";

	const client = createVertaauxClient({
	  apiKey: "your_api_key_here",
	  baseUrl: "https://vertaaux.ai/v1", // or staging host
	  idempotencyKey: generateIdempotencyKey(),
	});

const audit = await client.createAudit({ url: "https://example.com", mode: "basic" });
const status = await client.getAudit(audit.job_id);

See docs/SDK-QUICKSTART.md and sdk/js/README.md for publish steps.

Python

pip install -e ./sdk/python
from vertaaux_api_client import AuthenticatedClient
from vertaaux_api_client.api.audits import create_audit, get_audit
from vertaaux_api_client.models import AuditRequest

	client = AuthenticatedClient(
	    base_url="https://vertaaux.ai/v1",
	    token="YOUR_API_KEY",
	)
resp = create_audit.sync(client=client, json_body=AuditRequest(url="https://example.com", mode="basic"))
status = get_audit.sync(client=client, job_id=resp.job_id)

Generated from OpenAPI; update sdk/python/pyproject.toml before publishing.

Making Your First Request

  1. Set your API key in a secure env variable.
  2. POST to /audit with a fully qualified URL.
  3. Save the returned job_id.
  4. Poll for status or subscribe via webhook.
cURL
curl -X POST https://vertaaux.ai/v1/audit \
  -H "X-API-Key: $VERTAA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "mode": "standard"
  }'
JavaScript (fetch)
const response = await fetch("https://vertaaux.ai/v1/audit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "your_api_key_here",
  },
  body: JSON.stringify({ url: "https://example.com", mode: "standard" }),
});

const { job_id } = await response.json();
Python (requests)
import os, requests

api_key = os.environ["VERTAA_API_KEY"]
payload = {"url": "https://example.com", "mode": "standard"}

res = requests.post(
    "https://vertaaux.ai/v1/audit",
    headers={"X-API-Key": api_key, "Content-Type": "application/json"},
    json=payload,
)
print(res.json()["job_id"])

Poll until complete

cURL
curl -X GET https://vertaaux.ai/v1/audit/{job_id} \
  -H "X-API-Key: $VERTAA_API_KEY"
JavaScript (fetch)
const res = await fetch(`https://vertaaux.ai/v1/audit/${jobId}`, {
  headers: { "X-API-Key": "your_api_key_here" },
});
const audit = await res.json();

if (audit.status === "completed") {
  console.log(audit.scores, audit.issues?.length);
}

Audit Flows

Use the same endpoint for different targets. Choose mode to control depth: basic,standard, or deep.

Web (single-page)

  • Pass the page URL in the body.
  • Use mode: basic for faster screening or deep for thorough coverage.
  • Store the job_id to retrieve scores and issues later.
cURL
curl -X POST https://vertaaux.ai/v1/audit \
  -H "X-API-Key: $VERTAA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://shop.example.com/checkout",
    "mode": "deep"
  }'

Multi-page runs

  • Send one POST /audit per URL and aggregate results on your side.
  • Throttle concurrency to respect rate limits and avoid 429 responses.
  • Use webhooks to reduce polling load when running larger batches.
JavaScript
const urls = [
  "https://example.com/",
  "https://example.com/pricing",
  "https://example.com/checkout",
];

const results = [];
for (const url of urls) {
  const res = await fetch("https://vertaaux.ai/v1/audit", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": "your_api_key_here",
    },
    body: JSON.stringify({ url, mode: "standard" }),
  });
  results.push(await res.json());
}
console.log(results.map((r) => r.job_id));

Responses & Error Codes

The audit status endpoint returns the full payload once processing is complete. Common HTTP responses are listed below.

Sample completed audit

{
  "job_id": "audit_01HF2YAJDQZ98X2M2YB1T5R9SJ",
  "status": "completed",
  "progress": 100,
  "scores": {
    "usability": 92,
    "clarity": 88,
    "ia": 86,
    "accessibility": 90,
    "performance": 82
  },
  "issues": [
    {
      "id": "iss_001",
      "severity": "high",
      "category": "accessibility",
      "description": "Button lacks accessible label",
      "recommendation": "Add aria-label or text content.",
      "selector": "button.primary",
      "wcag_reference": "2.5.3"
    }
  ],
  "heatmap_prediction": "https://cdn.example.com/heatmaps/audit_01HF2YA.png",
  "version": "1.0.0"
}

CI/CD gating: send fail_on_score or fail_on_drop with POST /audit. Responses include gating.failed and gating.reason when thresholds are crossed.

Success codes

  • 202 Accepted — audit queued; returns job_id.
  • 200 OK — current audit status or completed result.
  • 204 No Content — webhook deleted.

Error codes

  • 400 Bad Request — malformed body (e.g., missing URL).
  • 401 Unauthorized — missing or invalid API key.
  • 404 Not Found — unknown job_id.
  • 429 Too Many Requests — rate limit exceeded.
  • 500 — transient error; retry with backoff.

Error format

{
  "error": "Validation error",
  "message": "Quota exceeded",
  "details": [...]
}

On 429, use Retry-After and backoff; SDK retries handle this by default. Responses include X-API-Version and ruleset_version for traceability.

  • Reduce concurrency or move to webhooks to avoid heavy polling.
  • Check GET /quota before large batches.

Pagination

Issue payloads support server-side filtering and pagination to avoid oversized responses. Use page and per_page on GET /audit/{job_id} to page through issues. Filters:severity=error|warning|info and fields=severity,selector,category to trim the payload. Responses include total and total_pages.

Streaming is available for large sets: GET /audit/{job_id}/issues/stream returns NDJSON so you can process issues incrementally.

Webhooks

Receive a POST callback when an audit finishes. Register a target URL and optional signing secret using POST /webhooks.

Delivery logs & replay

  • List deliveries: GET /api/webhooks/logs (filter by webhook_id).
  • Replay a delivery: POST /api/webhooks/logs with delivery_id.

Signature verification

// Node/TS
import { verifyWebhookSignature } from "@vertaaux/sdk-js";
const isValid = await verifyWebhookSignature({
  secret: "your_webhook_secret_here",
  payload: rawBodyString,
  signature: req.headers["x-vertaaux-signature"] as string,
  timestamp: req.headers["x-vertaaux-signature-timestamp"] as string,
  toleranceSeconds: 300,
});
# Python
import hmac, hashlib, time

def verify(secret: str, payload: str, signature: str, timestamp: str, tolerance_seconds: int = 300) -> bool:
    try:
        ts_int = int(timestamp)
    except (TypeError, ValueError):
        return False
    if abs(time.time() - ts_int / 1000) > tolerance_seconds:
        return False
    digest = hmac.new(secret.encode(), f"{timestamp}.{payload}".encode(), hashlib.sha256).hexdigest()
    if len(digest) != len(signature):
        return False
    return hmac.compare_digest(digest, signature)

Webhooks include X-Vertaaux-Signature and X-Vertaaux-Signature-Timestamp. Signatures are HMAC-SHA256 overtimestamp.payload (millisecond timestamp). Reject stale requests (>5 minutes).

cURL
curl -X POST https://vertaaux.ai/v1/webhooks \
  -H "X-API-Key: $VERTAA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/vertaa",
    "secret": "your-shared-secret"
  }'
Node (verify + respond)
import crypto from "crypto";
import { NextRequest, NextResponse } from "next/server";

const secret = "your_webhook_secret_here";

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const signature = req.headers.get("x-vertaaux-signature") ?? "";
  const timestamp = req.headers.get("x-vertaaux-signature-timestamp") ?? "";

  if (!timestamp || Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) {
    return NextResponse.json({ ok: false, reason: "stale" }, { status: 400 });
  }

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  if (signature !== expected) return NextResponse.json({ ok: false }, { status: 401 });
  const payload = JSON.parse(rawBody);
  // payload.job_id, payload.status, payload.completed_at, payload.scores
  return NextResponse.json({ received: true });
}

Webhook expectations

  • Payload includes job_id, status, timestamps, scores, and issues if completed.
  • Return any 2xx status to acknowledge delivery.
  • Use your shared secret to verify authenticity before processing.
  • Delivery attempts: 6 retries over ~24h with exponential backoff; signature headers include X-Vertaaux-Signature and X-Vertaaux-Signature-Timestamp. Reject stale requests (>5 minutes).

Rate Limiting & Quotas

The API enforces per-account limits based on your subscription tier. Exceeding limits returns 429 Too Many Requests with rate limit headers.

Tier Limits

  • Free: Limited audits for evaluation
  • Pro: Higher limits with API access
  • Agency: Organization features + scheduled audits (up to 20)
  • Enterprise: Unlimited audits + scheduled audits (up to 100)

Best Practices

  • Use GET /api/v1/quota to check remaining quota before large batch operations.
  • Implement exponential backoff when receiving 429 responses.
  • Use webhooks instead of polling to reduce API calls.
  • For scheduled monitoring, use the Scheduled Audits feature instead of cron jobs.

Next.js Integration

Complete guide for integrating Vertaa in Next.js applications. Covers App Router, Pages Router, webhooks with signature verification, polling with exponential backoff, and caching patterns. Expected integration time: <30 minutes.

What's Included:

  • App Router: Server Components, Route Handlers, Server Actions
  • Pages Router: API routes, getServerSideProps patterns
  • Webhook handler with HMAC-SHA256 signature verification
  • Polling with exponential backoff (1s → 2s → 4s → 8s)
  • Caching strategies: Next.js cache, Redis, in-memory LRU
  • TypeScript types and best practices
View Next.js Guide →

SDK Examples

Use your preferred HTTP client; the API is language-agnostic. These snippets show minimal wrappers for common tasks.

Node + Axios
import axios from "axios";

const client = axios.create({
  baseURL: "https://vertaaux.ai/v1",
  headers: { "X-API-Key": "your_api_key_here" },
});

export async function runAudit(url: string) {
  const { data } = await client.post("/audit", { url, mode: "basic" });
  return data.job_id;
}
Python
import requests, os

BASE_URL = "https://vertaaux.ai/v1"
HEADERS = {"X-API-Key": os.environ["VERTAA_API_KEY"]}

def get_quota():
    res = requests.get(f"{BASE_URL}/quota", headers=HEADERS, timeout=10)
    res.raise_for_status()
    return res.json()

def delete_webhook(webhook_id: str):
    res = requests.delete(f"{BASE_URL}/webhooks/{webhook_id}", headers=HEADERS)
    return res.status_code == 204

API Explorer

Interactive Swagger UI documentation for testing API endpoints directly from your browser. Explore schemas, try live requests, and generate code snippets.

Open API Explorer →

Troubleshooting

Common issues

  • 401 Unauthorized: confirm X-API-Key header is present and correct.
  • 404 Not Found: verify the job_id exists and belongs to your account.
  • 429 Too Many Requests: reduce concurrency and retry after the reset time.
  • Timeouts: use mode: basic for faster responses or increase your client timeout.

Support checklist

  • Include job_id and timestamp when contacting support.
  • Share the HTTP status code and response body you received.
  • Redact secrets before sending logs or examples.
Contact Support

Scheduled Audits

Enterprise and Agency tiers can configure recurring audits with cron expressions. Receive email and webhook notifications when scores drop or audits fail.

Features

  • Automated recurring audits (5-minute to monthly intervals)
  • Email and webhook alerts for failures and score drops
  • Score threshold monitoring with delta tracking
  • Complete run history with trend analysis
  • Dashboard management for all schedules

API Endpoints

  • POST /api/v1/schedules - Create schedule
  • GET /api/v1/schedules - List schedules
  • PATCH /api/v1/schedules/{id} - Update schedule
  • DELETE /api/v1/schedules/{id} - Delete schedule

See docs/SCHEDULED-AUDITS.md for deployment guide.

Organizations & SSO

Agency and Enterprise tiers support multi-tenant organizations with SSO auto-join capabilities for domain-based onboarding.

Features

  • Domain-based SSO auto-join (Google, GitHub, Azure AD)
  • Role-based access control (Owner, Admin, Editor, Viewer)
  • White-label branding for PDFs and reports
  • Organization-scoped audits and API keys
  • Complete activity logging for compliance

Organization-Scoped Audits

Include organization_id in audit requests to apply organization branding and associate results with your team.

{
  "url": "https://example.com",
  "mode": "standard",
  "organization_id": "org_xxxxx"
}

Error Codes Reference

Comprehensive catalog of all API error codes with causes, resolutions, and examples.

View Error Codes →

Versioning & Deprecation Policy

Learn about our API version lifecycle, breaking change notifications, and 12-month deprecation process.

View Versioning Policy →

Service Level Agreement

Uptime and response-time targets available via Enterprise agreement, plus incident-response commitments and credits (by contract).

View Enterprise SLA →