Hosted Endpoints
Hosted endpoints run models we host ourselves — image, video and other worker images — and return a job you poll or receive by webhook. Every endpoint declares its own named inputs and outputs; the catalog below is generated live from the API, so it always matches what is deployed.
POST /api/v1/{prefix}/{slug}
- Auth: Bearer key with the
generate:imagescope (granted to keys by default). - Requires: a positive credit balance (otherwise
402).
Like LLM endpoints, hosted endpoints are not all served under one fixed segment: the prefix is chosen per endpoint. The catalog below publishes each endpoint's full path — use it verbatim rather than assembling a URL from the slug.
Request body
Every hosted endpoint takes the same envelope. Only the contents of inputs differ, and those are
what the catalog below documents per endpoint.
| Field | Type | Required | Notes |
|---|---|---|---|
inputs | object | ✓ | The endpoint's own named inputs. Unknown keys are rejected. |
webhook_url | string | - | HTTPS URL notified when the job finishes. Falls back to your account-level webhook. The callback is signed — see Webhooks. |
Media inputs
Image, video and audio inputs are URLs the worker downloads directly. They must be publicly
fetchable over HTTP or HTTPS; private or internal addresses are rejected with 400 before anything
is charged.
Response
A successful call returns 202 Accepted immediately — the job runs asynchronously:
{ "job_id": "64b7f5a6-f341-47c7-9c1e-7d13f6391cc6", "status": "queued" }
Then either poll or wait for the webhook:
GET /api/v1/{prefix}/jobs/{job_id}
(The generic GET /api/v1/jobs/{job_id} returns the same answer.)
:::danger Verify the webhook signature Every callback carries a Standard Webhooks signature. Verify it before you act on the payload. See Webhooks. :::
A completed job carries status and an outputs object with one typed field per declared output.
Media outputs are presigned URLs into our storage, valid for a limited time — download what you
need when you receive them. A failed job carries error and error_code — see
Jobs.
Seed
Some endpoints take a seed. When you omit it, we draw one at random, so each call gives a
different output. The job reports the seed it ran with as seed, in the poll result and in the
completion webhook:
{
"result": {
"outputs": { "image": { "media_id": "…", "url": "…" } },
"seed": 813402917
}
}
To reproduce an output, send the same inputs with that seed on the next call. When you send a
seed yourself, the job reports that value. seed is absent when the endpoint takes no seed.
Example
curl -X POST https://api.phantomrouter.ai/api/v1/{prefix}/{slug} \
-H "Authorization: Bearer $PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": { "prompt": "a lighthouse at dusk", "image": "https://example.com/reference.png" }
}'
Each card in the catalog below carries a copyable command with that endpoint's real fields already filled in.
Errors
| Status | Code | When |
|---|---|---|
| 400 | INVALID_REQUEST | An input failed validation, or an unknown key was sent. |
| 401 | UNAUTHORIZED | Missing or invalid key. |
| 402 | PAYMENT_REQUIRED | Insufficient credit balance. |
| 403 | FORBIDDEN | Key lacks generate:image. |
| 404 | NOT_FOUND | No such endpoint — or one your key cannot reach. See below. |
404 is not always a typoEndpoints can be restricted to keys holding an extra scope. A restricted endpoint returns exactly
the same 404 as one that does not exist. If an endpoint you were told about returns 404, ask for
the scope rather than assuming the slug is wrong — the catalog below lists only the endpoints open
to every key holding generate:image.
Catalog
Every published hosted endpoint, with its exact request contract. Generated live from the API, so a change in the console appears here without a docs deploy.
The same data is served as JSON at GET /api/v1/public/hosted — unauthenticated, CORS-open, and
ETag-cached. Each endpoint is also available on its own at GET /api/v1/public/hosted/{slug}. Read
each entry's path for the URL to call. The per-endpoint schema_version changes only when the
contract itself changes, and matches the authenticated GET /api/v1/{prefix}/{slug}/schema.
Loading the live endpoint catalogue from /api/v1/public/hosted. It is also readable directly as raw catalogue JSON — no key required.