Skip to main content

What you’ll do

Submit an image (generated by any tool, not just a Runflow run) for quality evaluation, then read back a pass verdict, a 0.0-1.0 score, and the specific issues found. See Evaluations for the concepts behind this flow.

Prerequisites

  • A Runflow API key with the evaluations:create and evaluations:read scopes (create to submit, read to poll the result). Create one.
  • An image to evaluate, reachable as an HTTPS URL, a runflow://assets/{uuid} reference, or a data: URI.
  • Enough credit balance to cover one evaluation (submission pre-flights the balance).

Steps

1

Check the price (optional)

Job classes carry per-class prices. Read them at runtime instead of hardcoding:
curl https://api.runflow.io/v1/evaluations/job-classes \
  -H "Authorization: Bearer $RUNFLOW_API_KEY"
Today standard is the only active class. The price is frozen onto your evaluation at submission.
2

Submit the image

POST /v1/evaluations. Only generated_image_url and task_type are required; generation_prompt is optional but improves prompt-adherence judging.
curl -X POST https://api.runflow.io/v1/evaluations \
  -H "Authorization: Bearer $RUNFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7e3b1c9a-headshot-42" \
  -d '{
    "generated_image_url": "https://example.com/headshot.png",
    "task_type": "headshot",
    "task_description": "LinkedIn-ready corporate headshot",
    "generation_prompt": "studio lighting, neutral background",
    "client_ref": "customer-job-123"
  }'
The response is 202 Accepted with a pending evaluation. Keep the id.
{
  "id": "a1b2c3d4-5e6f-7890-abcd-ef1234567890",
  "status_code": "pending",
  "job_class_code": "standard",
  "client_ref": "customer-job-123"
}
The id is a UUID. Send the Idempotency-Key header so a retried submit does not create (and bill) a second evaluation.
3

Wait for the verdict

Evaluation is asynchronous and usually takes tens of seconds. Choose one:
Fetch the evaluation until status_code is terminal (completed or failed). Replace {id} with the id from the previous step.
curl https://api.runflow.io/v1/evaluations/{id} \
  -H "Authorization: Bearer $RUNFLOW_API_KEY"
const BASE = "https://api.runflow.io";

async function waitForVerdict(id) {
  const deadline = Date.now() + 2 * 60 * 1000; // safety cap
  while (Date.now() < deadline) {
    const res = await fetch(`${BASE}/v1/evaluations/${id}`, {
      headers: { Authorization: `Bearer ${process.env.RUNFLOW_API_KEY}` },
    });
    if (!res.ok) {
      const err = await res.json().catch(() => ({}));
      throw new Error(`Polling failed (${res.status}): ${err.message ?? "unknown error"}`);
    }
    const evaluation = await res.json();
    if (["completed", "failed"].includes(evaluation.status_code)) {
      return evaluation;
    }
    await new Promise((r) => setTimeout(r, 5000));
  }
  throw new Error("Timed out waiting for a terminal evaluation status");
}
4

Read the result

On a completed evaluation, read the verdict:
{
  "id": "a1b2c3d4-5e6f-7890-abcd-ef1234567890",
  "status_code": "completed",
  "overall_passed": true,
  "weighted_pass_rate": 0.92,
  "top_issues": ["Slight shadow under the chin"],
  "top_strengths": ["identity", "framing"],
  "primary_action_code": null,
  "cost": "0.400000"
}
weighted_pass_rate is a number (0.0-1.0); cost is a decimal string of credits charged; top_issues is a list of short labels. Use overall_passed for a yes/no gate and weighted_pass_rate for a threshold. For the per-judge breakdown (each issue with its category / subcategory / detail), request embeds: GET /v1/evaluations/{id}?embed=judges,action,gate_failures.

Verify it worked

curl https://api.runflow.io/v1/evaluations/{id} \
  -H "Authorization: Bearer $RUNFLOW_API_KEY"
status_code is completed and overall_passed / weighted_pass_rate are populated. You’re done.

Add reference images

For identity or garment checks, attach up to 4 reference images. Each accepts the same three URL forms as generated_image_url.
curl -X POST https://api.runflow.io/v1/evaluations \
  -H "Authorization: Bearer $RUNFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "generated_image_url": "https://example.com/generated.png",
    "task_type": "headshot",
    "reference_images": [
      { "url": "https://example.com/source-face.png", "kind": "source_face", "description": "The person to match" }
    ]
  }'
To avoid sending public URLs, upload the file first and pass a runflow://assets/{uuid} reference. See Upload large files.

Troubleshooting

SymptomLikely causeFix
402 on submitBalance below the job-class priceTop up, then resubmit.
422 on submitBad bodyCheck task_type is set, text is under length caps, <= 4 reference images, and media URLs are https:// (not http://).
429 on submitToo many in-flight evaluationsWait for some to finish, then retry.
403 on submitKey lacks evaluations:createRecreate the key with the scope.
Terminal failedSee failure_codeinvalid_media means a URL could not be fetched; only processing_failed and completed are billed.

Evaluations concept

Lifecycle, scoring, job classes, billing.

Handle async callbacks

Receive terminal evaluations by POST.

Upload large files

The runflow:// reference flow for local images.

API reference

POST /v1/evaluations and friends.