Документація API
Довідник REST API v1 Pandus: автентифікація, ліміти, помилки, пагінація, кожен ендпоінт із параметрами та прикладами на curl, JavaScript, PHP і Python, підписані вебхуки.
- Версія:
- 1.1
- Базова URL:
- https://pandus.online/api/v1
- Оновлено:
Специфікація OpenAPI (YAML) Для чого потрібен API
API повертає результати автоматичної перевірки, а не повного аудиту. Це не юридична консультація.
Початок роботи
API Pandus дає ті самі автоматичні перевірки доступності, що й кабінет, у ваших власних інструментах: у скрипті деплою, панелі агенції, системі задач. Кожна відповідь — це автоматична перевірка, а не повний аудит, і не юридична консультація.
- API входить у тарифи Pro та Agency, дивіться ціни.
- У кабінеті відкрийте API і webhooks та створіть токен. Скопіюйте його одразу: його показують лише один раз.
- Зберігайте токен на своєму сервері, наприклад у змінній середовища
PANDUS_TOKEN, і надішліть перший запит:
curl https://pandus.online/api/v1/account \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
Відповідь показує ваш тариф, його ліміти та скільки з них використано. Далі типова інтеграція додає сайт (POST /sites), чекає на перевірку (GET /scans/{scan} або вебхук scan.completed) і читає звіт у JSON чи PDF.
Усі файли перевірки є і в API: PDF-звіт, експорт проблем (CSV, JSON, задачі GitHub, імпорт у Jira) і на тарифах Agency — чернетка ACR у JSON, HTML або PDF. GET /sites/{site}/export повертає файл останньої завершеної перевірки сайту, не шукаючи перевірку окремо. PDF створюються синхронно, уперше — до хвилини: тримайте тайм-аут читання клієнта 120 секунд.
Усі адреси нижче відносні до базової URL https://pandus.online/api/v1. Запити й відповіді — JSON в UTF-8 (PDF, скриншоти й експорти — файли); дати — ISO 8601 із часовим поясом. Машиночитний опис усього, що є на цій сторінці, — специфікація OpenAPI.
Автентифікація
Надсилайте токен у заголовку Authorization кожного запиту:
Authorization: Bearer 12|pNd4sY…
Accept: application/json
- Токен належить команді, а не людині, тож він працює й тоді, коли хтось іде з команди.
- Права.
readдає всі запитиGET.write— додавання й видалення сайтів і запуск перевірок. Для панелі достатньо токена лише для читання. - Відкликання. Видаліть токен у кабінеті, і він одразу перестане працювати. Cookie сесії кабінету API ніколи не приймає.
- Тариф. Якщо команда переходить на тариф без API, її токени відповідають
403, доки тариф знову не міститиме API; їх не видаляють. - Тримайте його в таємниці. Не вставляйте токен у код, що виконується в браузері, чи в публічний репозиторій. Використовуйте окремий токен для кожної інтеграції, щоб відкликати один, не зачіпаючи інших.
Ліміти
- Запити: 60 на хвилину на токен. PDF-звіт, експорт проблем і файли ACR: 20 на хвилину.
- Кожна відповідь містить
X-RateLimit-LimitіX-RateLimit-Remaining. Понад ліміт ви отримаєте429зRetry-After(скільки секунд чекати) таX-RateLimit-Reset(час Unix). - Ліміти тарифу діють як у кабінеті: кількість сайтів, сторінок за перевірку, скільки зберігаються перевірки (історія) і як часто можна запускати перевірку вручну: раз на годину для сайту і ніколи, поки триває перевірка цього сайту. Запит понад ліміт повертає
422з повідомленням. GET /accountповертає ліміти й використання, зокремаmanual_checks_available: кількість сайтів, на яких перевірку вручну можна запустити просто зараз.
Помилки
Помилки — це JSON із полем message англійською. Помилки валідації та ліміти тарифу (422) додають errors з проблемами за полями:
{
"message": "The url field is required. (and 1 more error)",
"errors": {
"url": ["The url field is required."],
"report_locale": ["The report locale field is required."]
}
}
| Статус | Значення |
|---|---|
401 |
Немає токена, або токен невідомий чи видалений. |
403 |
У токена немає потрібного права, тариф не містить API чи інструмента, або команду заблоковано. |
404 |
Не знайдено у вашій команді або старше за історію тарифу. Тіло завжди {"message": "Not found."}. |
409 |
Перевірка ще не завершена. |
422 |
Запит некоректний або його зупиняє ліміт тарифу. |
429 |
Забагато запитів: зачекайте Retry-After секунд. |
503 |
PDF зараз не вдалося підготувати: спробуйте за хвилину. |
Орієнтуйтеся на код статусу, а не на текст message: формулювання може змінюватися.
Пагінація
Списки (GET /sites і GET /sites/{site}/scans) приходять сторінками. per_page задає розмір від 1 до 100 (типово 50 сайтів або 20 перевірок), page — номер сторінки. Кожен список має три ключі:
data: елементи цієї сторінки;links:first,last,prevіnext, повні URL абоnull;meta:current_page,last_page,per_page,total,from,toіpath.
Щоб прочитати все, переходьте за links.next, доки він не стане null:
let url = 'https://pandus.online/api/v1/sites?per_page=100';
const sites = [];
while (url) {
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
const page = await response.json();
sites.push(...page.data);
url = page.links.next;
}
Вебхуки
Вебхуки повідомляють ваш сервер, коли щось стається, тож не треба постійно опитувати API. Додайте ендпоінт у кабінеті в розділі API і webhooks: публічну адресу https і події, які він слухає. Команда може мати до 5 ендпоінтів. Секрет (whsec_…) показують один раз, коли ендпоінт створено.
- Доставка.
POSTіз тілом JSON і заголовкамиPandus-Event,Pandus-DeliveryтаPandus-Signature. Переспрямування не виконуються; приватні й локальні адреси відхиляються. - Відповідайте будь-яким
2xxпротягом 10 секунд. Повільну роботу робіть після відповіді, наприклад у черзі. - Повтори. Інші відповіді й тайм-аути повторюються через 1 хвилину, 5 хвилин, 30 хвилин, 2 години й 6 годин.
Pandus-Deliveryоднаковий у кожному повторі: за ним відкидайте дублікати. Після 20 доставок, що не вдалися в жодній спробі, ендпоінт вимикається; увімкніть його знову в кабінеті. - Підпис.
Pandus-Signature: t=<час unix>,v1=<hex>.v1— це HMAC-SHA256 рядка"<t>.<сире тіло>"із секретом ендпоінта. Обчислюйте його по сирому тілу, до розбору JSON, порівнюйте за сталий час і відхиляйте мітки часу, старші за 5 хвилин.
Далі — події, їхні дані та перевірка підпису чотирма мовами.
scan.completed · Перевірку завершено
Sent for every completed check of a site of the team, scheduled or started by hand. A failed check sends no event. data.scan.links has ready-to-use API links to the report, the PDF, every export and the ACR draft.
Заголовки
| Ім’я | Опис |
|---|---|
| Pandus-Event | The event type, the same as type in the body. |
| Pandus-Delivery | ID of this delivery; the same on every retry, so you can ignore repeats. |
| Pandus-Signature | t=<unix time>,v1=<hex>. v1 is HMAC-SHA256 of "<t>.<raw body>" with the endpoint's secret (whsec_…). Compare it in constant time and refuse old timestamps (for example older than 5 minutes) against replays. |
Дані
{
"id": "evt_01j9z4c3x5v7b9n1m3k5j7h9g2",
"type": "scan.completed",
"created_at": "2026-10-14T06:03:42+00:00",
"data": {
"scan": {
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"kind": "scheduled",
"status": "completed",
"pages_requested": 2000,
"pages_scanned": 37,
"issues": 12,
"previous_issues": 15,
"by_impact": {
"critical": 2,
"serious": 7,
"moderate": 3
},
"error": null,
"queued_at": "2026-10-14T06:00:02+00:00",
"started_at": "2026-10-14T06:00:05+00:00",
"finished_at": "2026-10-14T06:03:41+00:00",
"links": {
"self": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8",
"report": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report",
"pdf": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf",
"exports": {
"json": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=json",
"csv": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv",
"github": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=github",
"jira": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=jira"
},
"acr": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr"
}
},
"site": {
"id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"url": "https://shop.example/",
"domain": "shop.example",
"name": "Example Shop",
"platform": "shopify",
"stack": [
"shopify"
],
"report_locale": "de",
"status": "active",
"tags": [
"client-a"
],
"next_scan_at": "2026-10-21T06:00:00+00:00",
"created_at": "2026-09-02T12:31:08+00:00"
},
"new_issues": 2
}
}
Any 2xx answer within 10 seconds marks the delivery as received. Other answers and timeouts are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours (6 attempts). After 20 deliveries that failed every attempt the endpoint is switched off.
issues.new · Перевірка знайшла нові проблеми
Sent after scan.completed when the check found problems that the previous check did not have (new_issues > 0). Same payload.
Заголовки
| Ім’я | Опис |
|---|---|
| Pandus-Event | The event type, the same as type in the body. |
| Pandus-Delivery | ID of this delivery; the same on every retry, so you can ignore repeats. |
| Pandus-Signature | t=<unix time>,v1=<hex>. v1 is HMAC-SHA256 of "<t>.<raw body>" with the endpoint's secret (whsec_…). Compare it in constant time and refuse old timestamps (for example older than 5 minutes) against replays. |
Дані
{
"id": "evt_01j9z4c3x5v7b9n1m3k5j7h9g3",
"type": "issues.new",
"created_at": "2026-10-14T06:03:42+00:00",
"data": {
"scan": {
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"kind": "scheduled",
"status": "completed",
"pages_requested": 2000,
"pages_scanned": 37,
"issues": 12,
"previous_issues": 15,
"by_impact": {
"critical": 2,
"serious": 7,
"moderate": 3
},
"error": null,
"queued_at": "2026-10-14T06:00:02+00:00",
"started_at": "2026-10-14T06:00:05+00:00",
"finished_at": "2026-10-14T06:03:41+00:00",
"links": {
"self": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8",
"report": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report",
"pdf": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf",
"exports": {
"json": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=json",
"csv": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv",
"github": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=github",
"jira": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=jira"
},
"acr": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr"
}
},
"site": {
"id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"url": "https://shop.example/",
"domain": "shop.example",
"name": "Example Shop",
"platform": "shopify",
"stack": [
"shopify"
],
"report_locale": "de",
"status": "active",
"tags": [
"client-a"
],
"next_scan_at": "2026-10-21T06:00:00+00:00",
"created_at": "2026-09-02T12:31:08+00:00"
},
"new_issues": 2
}
}
Any 2xx answer within 10 seconds marks the delivery as received. Other answers and timeouts are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours (6 attempts). After 20 deliveries that failed every attempt the endpoint is switched off.
ping · Тестова подія
Sent when you press "Send a test event" next to an endpoint in the cabinet. Every endpoint receives it, whatever events it listens to.
Заголовки
| Ім’я | Опис |
|---|---|
| Pandus-Event | The event type, the same as type in the body. |
| Pandus-Delivery | ID of this delivery; the same on every retry, so you can ignore repeats. |
| Pandus-Signature | t=<unix time>,v1=<hex>. v1 is HMAC-SHA256 of "<t>.<raw body>" with the endpoint's secret (whsec_…). Compare it in constant time and refuse old timestamps (for example older than 5 minutes) against replays. |
Дані
{
"id": "evt_01j9z5d9k1l3m5n7b9v1c3x5z7",
"type": "ping",
"created_at": "2026-10-14T09:20:11+00:00",
"data": {
"message": "Test event from Pandus."
}
}
Any 2xx answer within 10 seconds marks the delivery as received. Other answers and timeouts are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours (6 attempts). After 20 deliveries that failed every attempt the endpoint is switched off.
Перевірка підпису
Обчисліть HMAC-SHA256 від мітки часу, крапки й сирого тіла запиту із секретом ендпоінта, порівняйте з v1 за сталий час і відхиляйте мітки часу, старші за п’ять хвилин.
Shell
# SIGNATURE: the Pandus-Signature header; body.json: the raw request body.
t=$(printf '%s' "$SIGNATURE" | sed -E 's/.*t=([0-9]+).*/\1/')
v1=$(printf '%s' "$SIGNATURE" | sed -E 's/.*v1=([0-9a-f]+).*/\1/')
expected=$({ printf '%s.' "$t"; cat body.json; } \
| openssl dgst -sha256 -hmac "$PANDUS_WEBHOOK_SECRET" -r | cut -d' ' -f1)
[ "$expected" = "$v1" ] && echo "valid" || echo "invalid"
JavaScript
import crypto from 'node:crypto';
import express from 'express';
const app = express();
// The signature covers the raw body: read it before any JSON parser does.
app.post('/pandus/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const parts = Object.fromEntries(
(req.get('Pandus-Signature') ?? '').split(',').map((part) => part.split('=')),
);
const expected = crypto
.createHmac('sha256', process.env.PANDUS_WEBHOOK_SECRET)
.update(`${parts.t}.${req.body}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const valid =
fresh &&
typeof parts.v1 === 'string' &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!valid) return res.sendStatus(400);
const event = JSON.parse(req.body);
// event.type: "scan.completed", "issues.new" or "ping"
res.sendStatus(204);
});
PHP
// routes/api.php: no CSRF token on this route.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('pandus/webhook', function (Request $request) {
parse_str(str_replace(',', '&', (string) $request->header('Pandus-Signature')), $parts);
$expected = hash_hmac('sha256', ($parts['t'] ?? '').'.'.$request->getContent(), config('services.pandus.webhook_secret'));
abort_unless(
isset($parts['t'], $parts['v1'])
&& abs(time() - (int) $parts['t']) < 300
&& hash_equals($expected, (string) $parts['v1']),
400,
);
$event = $request->json()->all();
// $event['type']: scan.completed, issues.new or ping
return response()->noContent();
});
Python
import hashlib
import hmac
import os
import time
from flask import Flask, abort, request
app = Flask(__name__)
@app.post("/pandus/webhook")
def pandus_webhook():
header = request.headers.get("Pandus-Signature", "")
parts = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
body = request.get_data() # the raw body, before any parsing
secret = os.environ["PANDUS_WEBHOOK_SECRET"].encode()
signed = parts.get("t", "").encode() + b"." + body
expected = hmac.new(secret, signed, hashlib.sha256).hexdigest()
fresh = parts.get("t", "").isdigit() and abs(time.time() - int(parts["t"])) < 300
if not fresh or not hmac.compare_digest(expected, parts.get("v1", "")):
abort(400)
event = request.get_json()
# event["type"]: "scan.completed", "issues.new" or "ping"
return "", 204
Обліковий запис
Команда, якій належить токен, її тариф, ліміти й використання.
Тариф, ліміти й використання команди
GET
/account
Право токена: read
The team the token belongs to with its plan, what the plan includes and how much of it is used. Check usage before you add a site or start a check.
Відповідь
200 The team, plan, limits and usage.
application/json
{
"data": {
"team": {
"id": "01j9z3k8m4q2w7e5r6t8y0u1i2",
"name": "Nova Studio"
},
"plan": {
"code": "agency_10",
"name": "Agency 10",
"status": "active",
"ends_at": "2026-11-14T09:00:00+00:00",
"trial_ends_at": null
},
"features": {
"api": true,
"exports": true,
"white_label": true,
"statement_drafts": true,
"acr_drafts": true
},
"limits": {
"sites": 10,
"pages_per_check": 2000,
"check_frequency": "weekly",
"history_months": 24,
"seats": 5,
"manual_check_interval": "PT1H",
"requests_per_minute": 60
},
"usage": {
"sites": {
"used": 4,
"allowed": 10
},
"seats": {
"used": 2,
"allowed": 5
},
"manual_checks_available": 3
}
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/account" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/account', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/account')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/account",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Сайти
Сайти команди. Додавання сайту запускає його першу перевірку.
Список сайтів команди
GET
/sites
Право токена: read
Sites in alphabetical order of their domain, 50 a page by default.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| tag | query | string | Only sites with this tag, e.g. the name of an agency's client. |
| per_page | query | integer (1–100) |
Items per page, 1 to 100.
Типово: 50 |
| page | query | integer |
Page number, from 1.
Типово: 1 |
Відповідь
200 One page of sites.
application/json
{
"data": [
{
"id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"url": "https://shop.example/",
"domain": "shop.example",
"name": "Example Shop",
"platform": "shopify",
"stack": [
"shopify"
],
"report_locale": "de",
"status": "active",
"tags": [
"client-a"
],
"next_scan_at": "2026-10-21T06:00:00+00:00",
"created_at": "2026-09-02T12:31:08+00:00"
}
],
"links": {
"first": "https://pandus.online/api/v1/sites?page=1",
"last": "https://pandus.online/api/v1/sites?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "https://pandus.online/api/v1/sites?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "https://pandus.online/api/v1/sites",
"per_page": 50,
"to": 1,
"total": 1
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/sites?tag=client-a" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites?tag=client-a', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/sites', [
'tag' => 'client-a',
])
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/sites",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
params={
"tag": "client-a",
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Додати сайт
POST
/sites
Право токена: write
Adds a site to the team and queues its first check, unless scan is false. The address must be public: private networks, local addresses and blocked domains are refused with 422. The number of sites is limited by the plan.
Тіло запиту application/json
| Поле | Тип | Опис |
|---|---|---|
| url(обов’язковий) | string (max. 500) |
The address; https:// is added when left out.
|
| name | string | null (max. 120) | |
| report_locale(обов’язковий) | string |
Значення: en, uk, de, pl, cs, ro, ru |
| platform | string | null |
One platform key (older form of stack).
|
| stack | array of string (max. 8) |
Platform keys, e.g. shopify, woocommerce, wordpress, laravel, vue. Fixing tips follow the first shop platform.
|
| tags | array of string (max. 40) (max. 10) | |
| scan | boolean |
Start the first check right away.
Типово: true |
Приклад
{
"url": "shop.example",
"name": "Example Shop",
"report_locale": "de",
"stack": [
"shopify"
],
"tags": [
"client-a"
],
"scan": true
}
Відповідь
201 The new site.
application/json
{
"data": {
"id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"url": "https://shop.example",
"domain": "shop.example",
"name": "Example Shop",
"platform": "shopify",
"stack": [
"shopify"
],
"report_locale": "de",
"status": "active",
"tags": [
"client-a"
],
"next_scan_at": "2026-10-21T06:00:00+00:00",
"created_at": "2026-10-14T09:12:44+00:00"
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 422 | The request is not valid or a plan limit stops it. | The url field is required. (and 1 more error) |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl -X POST "https://pandus.online/api/v1/sites" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"url": "shop.example",
"name": "Example Shop",
"report_locale": "de",
"stack": [
"shopify"
],
"tags": [
"client-a"
],
"scan": true
}'
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'shop.example',
name: 'Example Shop',
report_locale: 'de',
stack: ['shopify'],
tags: ['client-a'],
scan: true,
}),
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->post('https://pandus.online/api/v1/sites', [
'url' => 'shop.example',
'name' => 'Example Shop',
'report_locale' => 'de',
'stack' => ['shopify'],
'tags' => ['client-a'],
'scan' => true,
])
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.post(
"https://pandus.online/api/v1/sites",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
json={
"url": "shop.example",
"name": "Example Shop",
"report_locale": "de",
"stack": ["shopify"],
"tags": ["client-a"],
"scan": True,
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Один сайт
GET
/sites/{site}
Право токена: read
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| site(обов’язковий) | path | string |
The site's id.
|
Відповідь
200 The site.
application/json
{
"data": {
"id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"url": "https://shop.example/",
"domain": "shop.example",
"name": "Example Shop",
"platform": "shopify",
"stack": [
"shopify"
],
"report_locale": "de",
"status": "active",
"tags": [
"client-a"
],
"next_scan_at": "2026-10-21T06:00:00+00:00",
"created_at": "2026-09-02T12:31:08+00:00"
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Видалити сайт
DELETE
/sites/{site}
Право токена: write
Deletes the site with all its checks, reports and screenshots. This cannot be undone.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| site(обов’язковий) | path | string |
The site's id.
|
Відповідь
204 Deleted; no body.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl -X DELETE "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
// 204 No Content
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->delete('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1')
->throw();
// 204 No Content
Python
import os
import requests
response = requests.delete(
"https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
# 204 No Content
Перевірки
Запустіть перевірку та стежте за її статусом.
Перевірки сайту
GET
/sites/{site}/scans
Право токена: read
Checks within the plan's history, newest first, 20 a page by default. The latest completed check of a site stays available even when it is older than the history.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| site(обов’язковий) | path | string |
The site's id.
|
| per_page | query | integer (1–100) |
Items per page, 1 to 100.
Типово: 20 |
| page | query | integer |
Page number, from 1.
Типово: 1 |
Відповідь
200 One page of checks.
application/json
{
"data": [
{
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"kind": "scheduled",
"status": "completed",
"pages_requested": 2000,
"pages_scanned": 37,
"issues": 12,
"previous_issues": 15,
"by_impact": {
"critical": 2,
"serious": 7,
"moderate": 3
},
"error": null,
"queued_at": "2026-10-14T06:00:02+00:00",
"started_at": "2026-10-14T06:00:05+00:00",
"finished_at": "2026-10-14T06:03:41+00:00",
"links": {
"self": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8",
"report": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report",
"pdf": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf",
"exports": {
"json": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=json",
"csv": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv",
"github": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=github",
"jira": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=jira"
},
"acr": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr"
}
}
],
"links": {
"first": "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans?page=1",
"last": "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans?page=3",
"prev": null,
"next": "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"links": [],
"path": "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans",
"per_page": 1,
"to": 1,
"total": 3
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Запустити перевірку зараз
POST
/sites/{site}/scans
Право токена: write
Queues a check of the site with the plan's number of pages. One check by hand per site an hour (a month on Free), never while a check of the site is running: both are answered with 422. Follow the status with "Status of a check" or a webhook.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| site(обов’язковий) | path | string |
The site's id.
|
Відповідь
202 The check is queued.
application/json
{
"data": {
"id": "01j9z5c1v3b5n7m9q1w3e5r7t9",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"kind": "manual",
"status": "queued",
"pages_requested": 2000,
"pages_scanned": 0,
"issues": null,
"previous_issues": null,
"by_impact": null,
"error": null,
"queued_at": "2026-10-14T09:15:00+00:00",
"started_at": null,
"finished_at": null,
"links": {
"self": "https://pandus.online/api/v1/scans/01j9z5c1v3b5n7m9q1w3e5r7t9",
"report": null,
"pdf": null,
"exports": null,
"acr": null
}
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 422 | A check of the site is running, or one was started by hand too recently. | You started a check of this site less than an hour ago. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl -X POST "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->post('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.post(
"https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/scans",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Статус перевірки
GET
/scans/{scan}
Право токена: read
The status (queued, running, completed, failed), the number of pages and problems.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
Відповідь
200 The check.
application/json
{
"data": {
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"kind": "scheduled",
"status": "completed",
"pages_requested": 2000,
"pages_scanned": 37,
"issues": 12,
"previous_issues": 15,
"by_impact": {
"critical": 2,
"serious": 7,
"moderate": 3
},
"error": null,
"queued_at": "2026-10-14T06:00:02+00:00",
"started_at": "2026-10-14T06:00:05+00:00",
"finished_at": "2026-10-14T06:03:41+00:00",
"links": {
"self": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8",
"report": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report",
"pdf": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf",
"exports": {
"json": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=json",
"csv": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv",
"github": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=github",
"jira": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=jira"
},
"acr": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr"
}
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Звіти
Результати завершеної перевірки: JSON, PDF, файли для розробників або порівняння.
Експорт останньої перевірки сайту
GET
/sites/{site}/export
Право токена: read
The same files as "Export the issues for developers", for the latest completed check of the site (the one its report shows), so you do not have to look up the check first. The Pandus-Scan header names the check the file is from. format=pdf is the PDF report (every plan with the API); the other formats come with paid plans. The PDF is prepared synchronously on the first request for a language (up to a minute, then kept); keep the read timeout of your client at 120 seconds. 20 requests a minute.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| site(обов’язковий) | path | string |
The site's id.
|
| format | query | string |
json (default) a JSON document; csv one row per element (UTF-8 with BOM); github Markdown with one GitHub issue per rule; jira a CSV for Jira's importer with one issue per rule; pdf the PDF report for the site's owner. GitHub and Jira files list problems (WCAG A/AA) only; CSV and JSON add the recommendations.
Значення: json, csv, github, jira, pdf Типово: json |
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The file as an attachment: Content-Disposition carries the file name, Pandus-Scan the check it is from. JSON, CSV (UTF-8 with BOM), Markdown or PDF by format.
application/json
{
"format": "accessibility-issues/1",
"disclaimer": "Automated check, not a full audit. Not legal advice.",
"generated_by": "Nova Studio",
"site": {
"name": "Example Shop",
"url": "https://shop.example/"
},
"checked_at": "2026-10-14T06:03:41+00:00",
"pages_checked": 37,
"standard": "WCAG 2.2 A/AA, EN 301 549",
"engine": {
"axe": "4.10.0"
},
"language": "en",
"rules": [
{
"rule": "button-name",
"type": "problem",
"severity": "critical",
"title": "Some buttons have no name",
"summary": "Some buttons have no readable label, for example an icon-only \"add to cart\", search or menu button.",
"how_to_fix": "Give every button a name: visible text, aria-label, or aria-labelledby pointing to visible text.",
"platform_tip": "Usually icon buttons in the theme or buttons injected by apps.",
"wcag": [
"4.1.2 Name, Role, Value (A)"
],
"en301549": [
"9.4.1.2"
],
"count": 1,
"pages": 1,
"issues": [
{
"page": "https://shop.example/cart",
"selector": ".cart-icon",
"html": "<button class=\"cart-icon\"></button>",
"failure_summary": "Fix any of the following: Element does not have inner text that is visible to screen readers",
"is_new": false
}
]
}
]
}
text/csv
rule,type,severity,wcag,title,page_url,selector,html,failure_summary,new_since_previous_check
button-name,problem,critical,"4.1.2 Name, Role, Value (A)","Some buttons have no name",https://shop.example/cart,.cart-icon,"<button class=""cart-icon""></button>","Fix any of the following",no
text/markdown
# Accessibility issues of Example Shop
> Automated check, not a full audit. Not legal advice.
## [critical] Some buttons have no name (button-name)
- [ ] https://shop.example/cart — `.cart-icon`
Labels: `accessibility`, `a11y:critical`, `axe:button-name`
application/pdf
Файл; приклад не показано.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | Without the ability read, without the API in the plan, or without exports in the plan (CSV, JSON, GitHub and Jira files; the PDF is in every plan with the API). |
Issue exports are not included in the current plan of this team. / Invalid ability provided. |
| 404 | The site is not in this team, or it has no completed check yet. | The site has no completed check yet. / Not found. |
| 422 | The request is not valid or a plan limit stops it. | The url field is required. (and 1 more error) |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
| 503 | The PDF could not be prepared right now; try again after Retry-After seconds. |
The PDF could not be prepared right now. Please try again in a minute. |
Приклади коду
curl
curl "https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/export?format=pdf&lang=de" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
--fail -o report.pdf
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/export?format=pdf&lang=de', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
await writeFile('report.pdf', Buffer.from(await response.arrayBuffer()));
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->get('https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/export', [
'format' => 'pdf',
'lang' => 'de',
])
->throw();
file_put_contents('report.pdf', $response->body());
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/sites/01j9z3m2c5v7b9n1m3k5j7h9g1/export",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}"},
params={
"format": "pdf",
"lang": "de",
},
timeout=30,
)
response.raise_for_status()
with open("report.pdf", "wb") as file:
file.write(response.content)
Звіт у JSON
GET
/scans/{scan}/report
Право токена: read
The owner report of a completed check, the same content as in the cabinet: problem groups with plain-language explanations and fixing tips, examples, affected pages, totals by severity, the comparison with the previous check and the trend. Recommendations (AAA, best practice) are under advisory. Screenshot URLs need the same token.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The report.
application/json
{
"data": {
"scan_id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"locale": "en",
"url": "https://shop.example/",
"title": "Example Shop",
"platform": "shopify",
"platform_name": "Shopify",
"checked_at": "2026-10-14T06:03:41.000000Z",
"screen": null,
"totals": {
"critical": 1,
"serious": 0,
"moderate": 0,
"minor": 0
},
"total": 1,
"groups": [
{
"rule": "button-name",
"severity": "critical",
"rank": 0,
"count": 1,
"new_count": 0,
"title": "Some buttons have no name",
"summary": "Some buttons have no readable label, for example an icon-only \"add to cart\", search or menu button.",
"impact": "Screen reader and voice control users cannot tell which button adds to cart, opens the menu or submits the search.",
"who": [
"blind customers",
"screen reader users",
"voice control users"
],
"how_to_fix": "Give every button a name: visible text, aria-label, or aria-labelledby pointing to visible text.",
"platform_tip": "Usually icon buttons in the theme or buttons injected by apps. Add labels in the theme's Liquid snippets.",
"machine": false,
"has_card": true,
"help": "Buttons must have discernible text",
"refs": [
"WCAG 2.2 4.1.2 (A) Name, Role, Value",
"EN 301 549 9.4.1.2"
],
"pages": [
{
"url": "https://shop.example/cart",
"count": 1
}
],
"examples": [
{
"id": 4182,
"page": "https://shop.example/cart",
"target": ".cart-icon",
"html": "<button class=\"cart-icon\"></button>",
"details": null,
"is_new": false,
"shot": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/evidence/issue/4182",
"shot_width": 1280,
"shot_height": 720
}
],
"boxes": [],
"n": 1
}
],
"advisory": [],
"pages": [
{
"url": "https://shop.example/cart",
"title": "Cart",
"issues": 1,
"error": null
}
],
"diff": {
"previous_id": "01j9yq3r5t7y9u1i3o5p7a9s1d",
"previous_date": "2026-10-07T06:02:57+00:00",
"previous_total": 2,
"new": 0,
"fixed": 1,
"remaining": 1,
"fixed_rules": [
{
"title": "Images have no text description",
"count": 1
}
]
},
"trend": [
{
"id": "01j9yq3r5t7y9u1i3o5p7a9s1d",
"date": "2026-10-07T06:02:57+00:00",
"total": 2
},
{
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"date": "2026-10-14T06:03:41+00:00",
"total": 1
}
]
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/report",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Звіт у PDF
GET
/scans/{scan}/pdf
Право токена: read
The PDF report of a completed check, under the team's brand on plans with white-label. Synchronous: the first request for a language prepares the file (up to a minute; keep the read timeout of your client at 120 seconds) and the next ones get the stored file. If the renderer is busy or down the answer is 503 with Retry-After. The same file as GET /scans/{scan}/export?format=pdf. 20 requests a minute.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The PDF file (Content-Disposition attachment).
application/pdf
Файл; приклад не показано.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
| 503 | The PDF could not be prepared right now; try again after Retry-After seconds. |
The PDF could not be prepared right now. Please try again in a minute. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf?lang=de" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
--fail -o report.pdf
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf?lang=de', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
await writeFile('report.pdf', Buffer.from(await response.arrayBuffer()));
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf', [
'lang' => 'de',
])
->throw();
file_put_contents('report.pdf', $response->body());
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/pdf",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}"},
params={
"lang": "de",
},
timeout=30,
)
response.raise_for_status()
with open("report.pdf", "wb") as file:
file.write(response.content)
Експорт проблем для розробників
GET
/scans/{scan}/export
Право токена: read
The issues of a completed check as a file for developers and ticket systems, the same files as the export menus in the cabinet. Included in paid plans (and for the check an express report was bought for). format=pdf returns the PDF report instead, as "The report as PDF" (every plan with the API). 20 requests a minute.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| format | query | string |
json (default) a JSON document; csv one row per element (UTF-8 with BOM); github Markdown with one GitHub issue per rule; jira a CSV for Jira's importer with one issue per rule; pdf the PDF report for the site's owner. GitHub and Jira files list problems (WCAG A/AA) only; CSV and JSON add the recommendations.
Значення: json, csv, github, jira, pdf Типово: json |
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The file as an attachment: Content-Disposition carries the file name, Pandus-Scan the check it is from. JSON, CSV (UTF-8 with BOM), Markdown or PDF by format.
application/json
{
"format": "accessibility-issues/1",
"disclaimer": "Automated check, not a full audit. Not legal advice.",
"generated_by": "Nova Studio",
"site": {
"name": "Example Shop",
"url": "https://shop.example/"
},
"checked_at": "2026-10-14T06:03:41+00:00",
"pages_checked": 37,
"standard": "WCAG 2.2 A/AA, EN 301 549",
"engine": {
"axe": "4.10.0"
},
"language": "en",
"rules": [
{
"rule": "button-name",
"type": "problem",
"severity": "critical",
"title": "Some buttons have no name",
"summary": "Some buttons have no readable label, for example an icon-only \"add to cart\", search or menu button.",
"how_to_fix": "Give every button a name: visible text, aria-label, or aria-labelledby pointing to visible text.",
"platform_tip": "Usually icon buttons in the theme or buttons injected by apps.",
"wcag": [
"4.1.2 Name, Role, Value (A)"
],
"en301549": [
"9.4.1.2"
],
"count": 1,
"pages": 1,
"issues": [
{
"page": "https://shop.example/cart",
"selector": ".cart-icon",
"html": "<button class=\"cart-icon\"></button>",
"failure_summary": "Fix any of the following: Element does not have inner text that is visible to screen readers",
"is_new": false
}
]
}
]
}
text/csv
rule,type,severity,wcag,title,page_url,selector,html,failure_summary,new_since_previous_check
button-name,problem,critical,"4.1.2 Name, Role, Value (A)","Some buttons have no name",https://shop.example/cart,.cart-icon,"<button class=""cart-icon""></button>","Fix any of the following",no
text/markdown
# Accessibility issues of Example Shop
> Automated check, not a full audit. Not legal advice.
## [critical] Some buttons have no name (button-name)
- [ ] https://shop.example/cart — `.cart-icon`
Labels: `accessibility`, `a11y:critical`, `axe:button-name`
application/pdf
Файл; приклад не показано.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | Without the ability read, without the API in the plan, or without exports in the plan (CSV, JSON, GitHub and Jira files; the PDF is in every plan with the API). |
Issue exports are not included in the current plan of this team. / Invalid ability provided. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 422 | The request is not valid or a plan limit stops it. | The url field is required. (and 1 more error) |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
| 503 | The PDF could not be prepared right now; try again after Retry-After seconds. |
The PDF could not be prepared right now. Please try again in a minute. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
--fail -o issues.csv
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export?format=csv', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
await writeFile('issues.csv', Buffer.from(await response.arrayBuffer()));
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export', [
'format' => 'csv',
])
->throw();
file_put_contents('issues.csv', $response->body());
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/export",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}"},
params={
"format": "csv",
},
timeout=30,
)
response.raise_for_status()
with open("issues.csv", "wb") as file:
file.write(response.content)
Порівняти дві перевірки
GET
/scans/{scan}/compare/{other}
Право токена: read
Before and after between two completed checks of one site, per rule: which problems (WCAG A/AA) were fixed, which are new and which are still open. Problems are matched by rule, page and element. Up to 25 elements are listed per rule and state; count has the full number.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| other(обов’язковий) | path | string | ID of another completed check of the same site. The older of the two is "before". |
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The comparison.
application/json
{
"data": {
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"locale": "en",
"before": {
"id": "01j9yq3r5t7y9u1i3o5p7a9s1d",
"date": "2026-10-07T06:02:57+00:00",
"issues": 3
},
"after": {
"id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"date": "2026-10-14T06:03:41+00:00",
"issues": 2
},
"totals": {
"fixed": 2,
"new": 1,
"open": 1,
"before": 3,
"after": 2
},
"rules": [
{
"rule": "button-name",
"title": "Some buttons have no name",
"severity": "critical",
"fixed": {
"count": 1,
"items": [
{
"page": "https://shop.example/cart",
"selector": ".wishlist"
}
]
},
"new": {
"count": 0,
"items": []
},
"open": {
"count": 1,
"items": [
{
"page": "https://shop.example/cart",
"selector": ".cart-icon"
}
]
}
},
{
"rule": "color-contrast",
"title": "Text is hard to read because of low contrast",
"severity": "serious",
"fixed": {
"count": 0,
"items": []
},
"new": {
"count": 1,
"items": [
{
"page": "https://shop.example/cart",
"selector": ".price"
}
]
},
"open": {
"count": 0,
"items": []
}
}
]
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 422 | The checks belong to different sites, or it is the same check twice. | Both checks must belong to the same site. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/compare/01j9yq3r5t7y9u1i3o5p7a9s1d" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/compare/01j9yq3r5t7y9u1i3o5p7a9s1d', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/compare/01j9yq3r5t7y9u1i3o5p7a9s1d')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/compare/01j9yq3r5t7y9u1i3o5p7a9s1d",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Скриншот зі звіту
GET
/scans/{scan}/evidence/{kind}/{id}
Право токена: read
The JPEG behind a shot or screen.url link of the JSON report.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| kind(обов’язковий) | path | string |
page for a page screenshot, issue for the screenshot of one element.
Значення: page, issue |
| id(обов’язковий) | path | integer |
The number from the report (examples[].id for an element).
|
Відповідь
200 The screenshot.
image/jpeg
Файл; приклад не показано.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | The token lacks the ability for this request, the team's plan does not include the API, or the team is blocked. | Invalid ability provided. / The API is not included in the current plan of this team. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/evidence/issue/4182" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
--fail -o screenshot.jpg
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/evidence/issue/4182', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
await writeFile('screenshot.jpg', Buffer.from(await response.arrayBuffer()));
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/evidence/issue/4182')
->throw();
file_put_contents('screenshot.jpg', $response->body());
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/evidence/issue/4182",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
with open("screenshot.jpg", "wb") as file:
file.write(response.content)
Чернетка ACR у форматі JSON
GET
/scans/{scan}/acr
Право токена: read
Draft of an Accessibility Conformance Report (VPAT 2.x terms) from a completed check: one entry per WCAG 2.2 A/AA criterion with the automated result and what a person entered. Agency plans. Only automated comes from the check (fails, no_failures, not_testable); conformance and remarks are only ever what a person sent, and "no automated failures" never becomes "supports". It is a draft, not a VPAT/ACR, until a person has evaluated every criterion (notice).
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The draft.
application/json
{
"data": {
"scan_id": "01j9z4a7d2f4g6h8j0k2l4z6x8",
"site_id": "01j9z3m2c5v7b9n1m3k5j7h9g1",
"locale": "en",
"notice": "Draft based on an automated check. Not a VPAT/ACR until a person has evaluated every criterion. Not legal advice.",
"generated_by": "Nova Studio",
"site": {
"name": "Example Shop",
"url": "https://shop.example/"
},
"checked_at": "2026-10-14T06:03:41+00:00",
"pages_checked": 37,
"standard": "WCAG 2.2 A/AA",
"engine": {
"axe": "4.10.0"
},
"counts": {
"fails": 6,
"no_failures": 17,
"not_testable": 32
},
"filled": 1,
"levels": [
"supports",
"partially_supports",
"does_not_support",
"not_applicable",
"not_evaluated"
],
"criteria": [
{
"criterion": "1.1.1",
"name": "Non-text Content",
"level": "A",
"url": "https://www.w3.org/WAI/WCAG22/Understanding/non-text-content",
"automated": "fails",
"failures": [
{
"rule": "image-alt",
"title": "Images without a text alternative",
"count": 4,
"pages": 2
}
],
"conformance": "partially_supports",
"remarks": "Product photos in the gallery have no alt text; fixed in the next release."
},
{
"criterion": "1.2.1",
"name": "Audio-only and Video-only (Prerecorded)",
"level": "A",
"url": "https://www.w3.org/WAI/WCAG22/Understanding/audio-only-and-video-only-prerecorded",
"automated": "not_testable",
"failures": [],
"conformance": null,
"remarks": null
}
],
"unmapped": [],
"links": {
"html": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export?format=html&lang=en",
"pdf": "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export?format=pdf&lang=en"
}
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | Without the ability the request needs, without the API in the plan, or without ACR drafts in the plan (Agency plans). | ACR drafts are not included in the current plan of this team. / Invalid ability provided. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json"
JavaScript
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr')
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Заповнити один критерій ACR
PUT
/scans/{scan}/acr/{criterion}
Право токена: write
Saves what a person decided for one criterion: the conformance level (VPAT 2.x terms, lower case as in levels) and remarks. A field left out keeps its value, null clears it; both empty removes the entry. Agency plans, ability write. Values are never set by Pandus itself: only what you send is stored. 60 requests a minute.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| criterion(обов’язковий) | path | string | Number of a WCAG 2.2 A/AA success criterion. 4.1.1 Parsing is not part of WCAG 2.2. |
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Тіло запиту application/json
| Поле | Тип | Опис |
|---|---|---|
| conformance | string | null |
Значення: supports, partially_supports, does_not_support, not_applicable, not_evaluated |
| remarks | string | null (max. 5000) |
Приклад
{
"conformance": "partially_supports",
"remarks": "Product photos in the gallery have no alt text; fixed in the next release."
}
Відповідь
200 The criterion as saved.
application/json
{
"data": {
"criterion": "1.1.1",
"name": "Non-text Content",
"level": "A",
"url": "https://www.w3.org/WAI/WCAG22/Understanding/non-text-content",
"automated": "fails",
"failures": [
{
"rule": "image-alt",
"title": "Images without a text alternative",
"count": 4,
"pages": 2
}
],
"conformance": "partially_supports",
"remarks": "Product photos in the gallery have no alt text; fixed in the next release."
}
}
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | Without the ability the request needs, without the API in the plan, or without ACR drafts in the plan (Agency plans). | ACR drafts are not included in the current plan of this team. / Invalid ability provided. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 422 | An unknown criterion, a level that is not one of levels, remarks over 5000 characters, or an empty body. |
The selected conformance is invalid. |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
Приклади коду
curl
curl -X PUT "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/1.1.1" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"conformance": "partially_supports",
"remarks": "Product photos in the gallery have no alt text; fixed in the next release."
}'
JavaScript
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/1.1.1', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
conformance: 'partially_supports',
remarks: 'Product photos in the gallery have no alt text; fixed in the next release.',
}),
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
const { data } = await response.json();
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->acceptJson()
->put('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/1.1.1', [
'conformance' => 'partially_supports',
'remarks' => 'Product photos in the gallery have no alt text; fixed in the next release.',
])
->throw();
$data = $response->json('data');
Python
import os
import requests
response = requests.put(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/1.1.1",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}", "Accept": "application/json"},
json={
"conformance": "partially_supports",
"remarks": "Product photos in the gallery have no alt text; fixed in the next release.",
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]
Завантажити чернетку ACR
GET
/scans/{scan}/acr/export
Право токена: read
The ACR draft as a PDF or an HTML file, under the team's brand on plans with white-label, the same file as in the cabinet. The draft wording is at the start, at the end and, in the PDF, in the footer of every page. Made on every request (remarks change), synchronously: keep the read timeout of your client at 120 seconds. Agency plans. 20 requests a minute.
Параметри
| Ім’я | Де | Тип | Опис |
|---|---|---|---|
| scan(обов’язковий) | path | string |
The check's id.
|
| format | query | string |
pdf (default) or html, a single file that opens in any browser.
Значення: pdf, html Типово: pdf |
| lang | query | string |
Report language; the site's report language when left out.
Значення: en, uk, de, pl, cs, ro, ru |
Відповідь
200 The file (Content-Disposition attachment, e.g. acr-draft-shop.example-2026-10-14.pdf).
application/pdf
Файл; приклад не показано.
text/html
Файл; приклад не показано.
| Статус | Коли | message |
|---|---|---|
| 401 | No token, an unknown token or a deleted one. | Unauthenticated. |
| 403 | Without the ability the request needs, without the API in the plan, or without ACR drafts in the plan (Agency plans). | ACR drafts are not included in the current plan of this team. / Invalid ability provided. |
| 404 | Not found in this team, or older than the plan's history. | Not found. |
| 409 | The check is still queued or running, or it failed. | The scan is not completed yet. |
| 422 | The request is not valid or a plan limit stops it. | The url field is required. (and 1 more error) |
| 429 | Too many requests in a minute. Wait Retry-After seconds. |
Too Many Attempts. |
| 503 | The PDF could not be prepared right now; try again after Retry-After seconds. |
The PDF could not be prepared right now. Please try again in a minute. |
Приклади коду
curl
curl "https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export?format=pdf&lang=en" \
-H "Authorization: Bearer $PANDUS_TOKEN" \
--fail -o acr-draft.pdf
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export?format=pdf&lang=en', {
headers: {
Authorization: `Bearer ${process.env.PANDUS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Pandus API: HTTP ${response.status}`);
await writeFile('acr-draft.pdf', Buffer.from(await response.arrayBuffer()));
PHP
use Illuminate\Support\Facades\Http;
$response = Http::withToken(env('PANDUS_TOKEN'))
->get('https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export', [
'format' => 'pdf',
'lang' => 'en',
])
->throw();
file_put_contents('acr-draft.pdf', $response->body());
Python
import os
import requests
response = requests.get(
"https://pandus.online/api/v1/scans/01j9z4a7d2f4g6h8j0k2l4z6x8/acr/export",
headers={"Authorization": f"Bearer {os.environ['PANDUS_TOKEN']}"},
params={
"format": "pdf",
"lang": "en",
},
timeout=30,
)
response.raise_for_status()
with open("acr-draft.pdf", "wb") as file:
file.write(response.content)