For AI agents: this page is also available as Markdown at https://docs.refabric.com/task-apis/recipes.md, and the index of every page is https://docs.refabric.com/llms.txt.

Task APIs

Recipes

Chains of tasks that turn one result into the input of the next, run one step at a time.

A recipe is not one job; you run each step. Every step is an ordinary POST /v1/tasks/{name} with its own job, its own estimate and its own charge. A recipe tells you which tasks to call in which order, and which output of one step goes into which input of the next.

The recipes are listed live by GET /v1/recipes: each entry has a name, a title, a summary and its steps — the task names, in order (List recipes).

{ "items": [ { "name": "<recipe name>", "title": "<what it makes>",
               "summary": "<one paragraph>", "steps": ["<first task>", "<next task>", "…"] } ] }

How a step feeds the next

A step's output is an address the next step takes as it is — no download, no re-upload:

The step deliversYou pass it asInto, for example
a file (art:…)that stringany media field: image, references[].image
a record (moodboard:…, brand_kit:…, …)that handlethe field that takes the record: moodboards, brand_kit
a part of a record (data.items[].url)that urlany media field

Read each step's handle from its result's files[].file (Asynchronous jobs).

Example: from a moodboard to a refined design

Each step waits for the previous job to end. run submits a task and returns its result.

import os, time, uuid, requests

API = "https://api.refabric.com/v1"
s = requests.Session()
s.headers["Authorization"] = f"Key {os.environ['REFABRIC_API_KEY']}"

def run(task, body):
    job = s.post(f"{API}/tasks/{task}", json=body, headers={"Idempotency-Key": str(uuid.uuid4())})
    job.raise_for_status()
    handle = job.json()
    while (status := s.get(handle["status_url"]).json())["lifecycle"] != "terminal":
        time.sleep(5)
    if status["outcome"] != "succeeded":
        raise RuntimeError(status["error"])
    return s.get(handle["result_url"]).json()

board = run("moodboard.create", {"kind": "brand_dna", "name": "Resort", "images": LOOK_URLS})
board_id = board["files"][0]["file"]                 # moodboard:…
designs = run("image.generate", {"prompt": "a relaxed linen shirt dress", "moodboards": [board_id]})
first = designs["files"][0]["file"]                  # art:…
refined = run("image.generate", {"prompt": "the same dress with short sleeves",
                                 "references": [{"image": first}]})

LOOK_URLS is your list of look images; moodboard.create states how many it takes. A moodboard must have finished its analysis before image.generate can use it: a board that is not ready is refused with moodboard_not_ready, so read it (GET /v1/files/moodboard:<id>) until its data.status is ready.

If a step fails

  • Each step is charged on its own. The steps that succeeded are charged for what they delivered; the step that failed is charged only for what it delivered before failing (Pricing).
  • What the earlier steps made stays yours. Continue from the failed step with the same inputs — you do not run the earlier steps again.
  • Before you retry a step, read its error's retryable (Task errors). Retry with the same Idempotency-Key only to repeat a submit whose answer you did not receive.