Skip to main content

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:image scope (granted to keys by default).
  • Requires: a positive credit balance (otherwise 402).
Each endpoint carries its own path prefix

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.

FieldTypeRequiredNotes
inputsobject✓The endpoint's own named inputs. Unknown keys are rejected.
webhook_urlstring-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​

StatusCodeWhen
400INVALID_REQUESTAn input failed validation, or an unknown key was sent.
401UNAUTHORIZEDMissing or invalid key.
402PAYMENT_REQUIREDInsufficient credit balance.
403FORBIDDENKey lacks generate:image.
404NOT_FOUNDNo such endpoint — or one your key cannot reach. See below.
A 404 is not always a typo

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

Generating a client?

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.