Skip to content

API Reference

Base URL: https://api.altpilot.app. Authenticated endpoints take your API key as a Bearer token: Authorization: Bearer <api_key>.

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.

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.

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).

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.

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.

DELETE /v1/account — session-token authenticated. Deletes your account and everything tied to it; irreversible. See Privacy & Data Retention.