Vertaa Developer DocsPublic API V1Beta

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/api/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.

Test / Staging

Use staging host https://staging-api.vertaaux.ai/v1 and test keys where available. Expect lower quotas and sandboxed results.

See docs/TEST-MODE.md for SDK/CLI overrides, fixtures, and webhook tips.

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: process.env.VERTAAUX_API_KEY! });
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: process.env.VERTAAUX_API_KEY!,
  baseUrl: "https://api.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://api.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/api/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/api/v1/audit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": process.env.VERTAA_API_KEY!,
  },
  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/api/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/api/v1/audit/{job_id} \
  -H "X-API-Key: $VERTAA_API_KEY"
JavaScript (fetch)
const res = await fetch(`https://vertaaux.ai/api/v1/audit/${jobId}`, {
  headers: { "X-API-Key": process.env.VERTAA_API_KEY! },
});
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/api/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/api/v1/audit", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": process.env.VERTAA_API_KEY!,
    },
    body: JSON.stringify({ url, mode: "standard" }),
  });
  results.push(await res.json());
}
console.log(results.map((r) => r.job_id));
WIP

Figma designs

  • Provide a Figma file or prototype share link as the url.
  • Ensure the link is accessible to the audit service (set to “can view” or use a secure shared link).
  • Results return the same structure: scores, issues, and optional heatmap predictions.
cURL
curl -X POST https://vertaaux.ai/api/v1/audit \
  -H "X-API-Key: $VERTAA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.figma.com/proto/your-shared-link",
    "mode": "standard"
  }'

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: process.env.VERTAAUX_WEBHOOK_SECRET!,
  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/api/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 = process.env.VERTAAUX_WEBHOOK_SECRET!;

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

The API enforces per-account limits to protect stability. Typical caps: Free 5 audits/day, Pro ~33/day (1000/month), Business 5000/month. Exceeding limits returns 429 Too Many Requests with X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After headers.

  • Distribute batch runs over time or use webhooks instead of rapid polling.
  • Retry after the reset timestamp provided in the response headers.
  • For sustained throughput needs, contact support for higher limits.

See docs/RATE-LIMITS.md for bucket behavior and Postman examples.

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/api/v1",
  headers: { "X-API-Key": process.env.VERTAA_API_KEY! },
});

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/api/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

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