HTTP API (user & admin)
The agent-swarm API is documented separately in [AGENT_API.md](AGENT_API.md). This page covers the platform API used by the dashboard, integrations and scripts.
- Base URL:
https://iya.ru/api/v1/ - Specification:
GET /api/v1/openapi.json(OpenAPI 3.1, generated from code) - Authentication:
Authorization: Bearer <api-token> - Envelope:
{ "ok": true, "data": …, "meta": … }/{ "ok": false, "error": { … } } - Versioning: the major version lives in the path (
/api/v1/…). Backwards
compatibility is guaranteed within a major version; breaking changes require a new major and a deprecation window announced in the changelog.
Tokens
Create tokens in Dashboard → API tokens. A token is shown once; only its SHA-256 hash is stored, together with a human-readable prefix (iya_u_9f3a…) so you can recognise it in a list.
Each token carries:
- scopes —
links:read,links:write,stats:read,subdomain:write,
team:read, admin (the last one only for staff roles);
- an optional IP allowlist (CIDR);
- an optional expiry;
last_used_at/last_used_ipfor auditing.
A token outside its scopes or allowlist answers 403 forbidden. Revoking is immediate.
Endpoints
Discovery & health
| Method | Path | Auth | Purpose |
| GET | /api/v1/ | – | API index |
| GET | /api/v1/health | – | liveness + dependency probe |
| GET | /api/v1/status | – | version, features, limits, counters |
| GET | /api/v1/openapi.json | – | OpenAPI 3.1 document |
| GET | /api/v1/errors | – | error catalogue |
| GET | /api/v1/languages | – | supported locales |
| GET | /metrics | – | Prometheus-style metrics |
Public read (no auth, owner-controlled)
| Method | Path | Notes |
| GET | /api/v1/subdomains/{name} | public page payload |
| GET | /api/v1/links?subdomain=… | public links |
| GET | /api/v1/stats?subdomain=… | aggregates, only if the owner enabled them |
| GET | /api/v1/visits?subdomain=… | recent visits, only if the list is public |
Each of these respects the subdomain's privacy policy: stats_public, stats_show_visits_list, stats_show_ip, stats_show_internal_ip, stats_show_geo, stats_show_ua, stats_show_referrer, stats_show_links, stats_show_owner, stats_publish_delay_sec and stats_max_items. Fields the owner hid are removed server-side, not merely hidden in the UI.
Authenticated
| Method | Path | Scope | Purpose | |||
| GET/POST | /api/v1/links | links:read / links:write | list and create links | |||
| GET/PATCH/DELETE | /api/v1/links/{id} | links:* | read, update, soft-delete | |||
| POST | /api/v1/links/{id}/duplicate | links:write | clone | |||
| GET | /api/v1/links/{id}/qr | links:read | QR code (SVG/PNG) | |||
| GET | /api/v1/stats/{scope}/{id} | stats:read | report data (subdomain, link, user) | |||
| GET | /api/v1/visits | stats:read | filtered visit list with cursor pagination | |||
| GET | `/api/v1/export?format=csv\ | json\ | xlsx\ | pdf` | stats:read | export |
| GET/POST | /api/v1/webhooks | subdomain:write | manage webhooks | |||
| GET/POST | /api/v1/tokens | – | manage API tokens |
Tracker (browser beacon)
| Method | Path | Purpose |
| GET/POST | /tracker/collect | consent-gated telemetry enrichment |
| POST | /tracker/consent | record a consent decision |
The beacon only ever adds client-side signals (time zone, screen, network, capability probes, and — with explicit consent — the LAN IP discovered via WebRTC). It can never change the server-determined ip_public.
Legacy compatibility
The original iya.ru v0 API is preserved so existing integrations keep working:
GET /api/rest.php/ip → current visitor
GET /api/rest.php/ip/{ip} → visitor by IP
GET /api/rest.php/visits?limit= → recent visits
GET /api/rest.php/bots → recent bots
GET /api/rest.php/hacks → recent attack attempts
GET /api/rest.php/stats → counters
New code should use /api/v1/…; the v0 shape is frozen and will only receive security fixes.
Pagination
Cursor-based for large collections:
{ "data": { "visits": [ … ] },
"meta": { "count": 50, "total": 183442, "limit": 50,
"cursor": "…", "next_cursor": "…", "has_more": true } }
Pass ?cursor=<next_cursor> for the following page. Offset pagination (?page=) is available for human-facing tables only.
Webhooks
Configure them in Dashboard → Account → Event webhooks. Events: visit.new, visit.unique, link.limit_reached, security.suspicious, link.created, link.target_down, agent.task. (Emitters shipped for all except link.target_down — lands with the target-health checker — and agent.task — lands with the swarm follow-ups; both are already accepted subscriptions.) The Test button delivers a webhook.test event outside the subscription.
- Payload: the same envelope, plus
eventanddelivered_at. - Signature:
X-Iya-Signature: sha256=<hmac>over the raw body with the
webhook secret. Verify it in constant time.
- Delivery: exponential backoff, 5 attempts, then the webhook is disabled and
the owner notified. Every attempt is logged (webhook_deliveries).
- Outbound requests go through the SSRF guard: private ranges, cloud metadata
endpoints and dangerous ports are refused.
Errors and debugging
See [ERRORS.md](ERRORS.md). Every response carries X-Request-Id; the same id appears in meta.request_id and in the server access log, which makes a single request traceable end to end.
Version 2.0.0 · Author: Mikhail Deynekin · icons@Deynekin.com · source: docs/API.md