API Reference
Base URL: https://api.altpilot.app. Authenticated endpoints take your API
key as a Bearer token: Authorization: Bearer <api_key>.
POST /v1/alttext
Section titled “POST /v1/alttext”Generate alt text and a caption for one image.
Body (JSON):
| Field | Type | Required | Notes |
|---|---|---|---|
image_url |
string | one of image_url/image_base64 |
Must be http/https; private/internal addresses are rejected. |
image_base64 |
string | one of image_url/image_base64 |
Raw base64 or a data: URI. |
context.page_title |
string | no | Hint for the model — improves relevance. |
context.nearby_text |
string | no | Surrounding page text, if you have it. |
context.lang |
string | no | Language hint for the generated text. |
Response 200:
{ "alt": "…", "caption": "…", "language": "en", "cached": false }cached: true means an identical image (by content hash) was already
processed — no model call, doesn’t count against quota-consuming behavior
differently, but is effectively free and instant.
Errors:
| Status | error |
Meaning |
|---|---|---|
| 401 | missing_api_key |
No Authorization header. |
| 401 | invalid_api_key |
Key not recognized or revoked. |
| 402 | quota_exceeded |
Free plan, over the monthly quota. Response includes an Upgrade-URL header. |
| 429 | rate_limited |
Per-key rate limit hit. Response includes a Retry-After header (seconds). |
| 502 | generation_failed |
The model call failed. |
| 503 | provider_unavailable |
The model provider is degraded; response includes Retry-After. |
| 400/4xx | (varies) | Bad input, or the image couldn’t be fetched (invalid URL, blocked host, too large, wrong content type). |
Paid plans don’t hard-stop at the quota — they’re billed metered overage instead of getting a 402. See pricing.
GET /v1/usage
Section titled “GET /v1/usage”Current billing-period usage for your account. Not rate-limited — cheap enough to poll from a dashboard or the WordPress plugin.
Response 200:
{ "period_start": "2026-09-01T00:00:00.000Z", "period_end": "2026-10-01T00:00:00.000Z", "included": 100, "used": 37, "overage": 0}Errors: 401 missing_api_key / 401 invalid_api_key, 404 account_not_found.
GET /v1/scan
Section titled “GET /v1/scan”Free, unauthenticated — the site scanner behind altpilot.app/scan. Crawls a domain’s images over HTTPS (retrying HTTP once), classifies which are missing or have weak alt text, and generates a few sample alt/caption pairs.
Query: ?domain=example.com
Response 200:
{ "domain": "example.com", "scannedAt": "2026-09-23T12:00:00.000Z", "totalImages": 42, "missing": 12, "weak": 5, "strong": 25, "samples": [{ "src": "…", "alt": "…", "caption": "…" }], "cached": false}Results are cached per domain for 30 days — a repeat scan of the same domain is instant.
Errors: 400 invalid_domain, 429 rate_limited (per-IP, no API key
needed), 502 scan_failed (the page couldn’t be fetched at all).
Authentication endpoints
Section titled “Authentication endpoints”The dashboard’s own signup/login/session flow — POST /v1/auth/signup,
POST /v1/auth/verify, POST /v1/auth/login, GET /v1/auth/me,
POST /v1/auth/logout, POST /v1/auth/apikey/rotate, plus Google sign-in.
These aren’t typically called directly by an API integration — see the
dashboard instead. Full detail lives in
apps/api/src/index.ts if you’re building your own client for them.
Billing endpoints
Section titled “Billing endpoints”POST /v1/billing/portal (Stripe Customer Portal link) and
GET /v1/billing/checkout-link back the dashboard’s “Manage plan” and
upgrade flows — session-token authenticated, not typically called from
your own integration.
Account deletion
Section titled “Account deletion”DELETE /v1/account — session-token authenticated. Deletes your account
and everything tied to it; irreversible. See
Privacy & Data Retention.