Map a queue-style API
Describe a submit-then-poll backend with a raw mapping, and make its jobs survive a restart.
Many media backends accept a task, answer with an id or a status URL, and deliver the output later. No preset covers these shapes, so you describe the calls directly in a raw mapping. The daemon renders the request for each job, polls until the task finishes, and extracts the result.
Write the mapping
models:
- model: black-forest-labs/flux-2-dev:fp8
modality: image
slas:
"24h": { rate_out: "12000" } # per output pixel, scaled by 10^6
backend:
request:
method: POST
url: https://queue.example.com/v1/models/flux-dev
headers: { Authorization: "Key env:QUEUE_BACKEND_KEY" }
body:
prompt: "{input.prompt}"
width: "{input.width}"
height: "{input.height}"
num_images: "{input.num_images}"
response:
mode: poll
poll:
status_url: "$.status_url" # JSONPath into the submit answer
status_field: "$.status" # JSONPath into each poll answer
done_values: [COMPLETED]
failed_values: [FAILED]
interval_s: 2
result:
media_urls: "$.images[*].url"
retries: 2{input.…}tokens read the job's decoded input. A token that is the whole string keeps the value's JSON type, sonum_imagesarrives as a number.env:NAMEworks inside any string. Raw mappings have nobase_urlorapi_keyparams: write the URL out and pull secrets from the environment.$.…values are JSONPath expressions evaluated against the backend's answers.resultnames exactly one output:media_urls(the daemon downloads each URL),media_b64(the daemon decodes each value), ortexttogether withcompletion_tokens.
Forward the metered fields
Image jobs are billed in output pixels (num_images × width × height) and video jobs in
pixel-seconds (width × height × duration_secs). Before rendering the request, the daemon
lowers num_images or duration_secs so the job fits the output cap the client paid for.
That only reaches the backend if the body forwards those fields. If you leave num_images
out, the backend renders the full request while you are paid for the reduced one.
Poll with a request instead of a URL
Some APIs poll by POSTing a task id. Replace status_url with a templated request. The
submit answer is in scope as {submit.…}:
poll:
request:
method: POST
url: https://api.example.com/tasks
body: [ { taskType: getResponse, taskUUID: "{submit.data[0].taskUUID}" } ]
status_field: "$.data[0].status"
done_values: [success]
failed_values: [error]Survive a restart
A job running at a queue backend keeps running if the daemon restarts. Name the field that
identifies it with handle, and poll with {handle} instead of {submit.…}:
poll:
request: { method: GET, url: "https://queue.example.com/v1/tasks/{handle}" }
handle: "$.task_id"
status_field: "$.status"
done_values: [COMPLETED]
failed_values: [FAILED]The daemon records the handle in provider.state_db as soon as the submit answers. After a
restart it resumes polling instead of submitting again, and on SIGTERM it parks the job
instead of waiting for it. A mapping that sets handle cannot use {submit.…} in its poll
request. See Stop and restart safely.
Handle APIs that answer 200 for everything
If the backend reports failures in the body rather than the HTTP status, tell the daemon where to look:
response:
ok: { field: "$.code", values: [200], retry: [429, 503], message: "$.msg" }Every JSON answer (submit, poll ticks and prepare steps) is checked. A value in retry is
retried like an HTTP 429; any other value outside values fails the job. The message is
written to your log only, never sent to the network.
For a task that ends in one of failed_values, poll.failure_code adds the backend's own
error code to the failure reason, and poll.failure_message logs its message.
Upload references first
A backend that takes an input image by URL rather than inline needs an upload before the
submit. Add prepare steps:
request:
prepare:
- name: first_frame
when: input.image # skipped when the job has no image
method: POST
url: https://files.example.com/upload
headers: { Authorization: "Bearer env:BACKEND_KEY" }
body: { data: "data:{input.image.media_type};base64,{input.image.b64}" }
extract: { url: "$.data.downloadUrl" }
method: POST
url: https://api.example.com/tasks
body:
prompt: "{input.prompt}"
first_frame_url: "{prepare.first_frame.url?}"The trailing ? marks an optional token. When it resolves to nothing, the whole key is left
out of the request. Uploading sends the client's reference to that storage, so point prepare
only at storage that belongs to the backend that will read it.
Complete example
queue-backend.yaml
is a complete image model served through a poll mapping.