all dispatches
AI Workflow PlatformSep 2, 20269 min read

Eachlabs for AI Model Routing and Media Workflows in 2026

Are you building an orchestration layer, or a growing collection of provider exceptions? Routing rules, production readiness, and multi-step media chains.

Eachlabs for AI Model Routing and Media Workflows in 2026

Every team that ships generative media arrives at the same fork, usually around month three. You picked a model. It works. Then a second use case needs a different model, a third needs video, someone asks for voiceover, and the model you picked in month one gets deprecated on a Tuesday.

At that point you're maintaining a switch statement over vendors, and you have to decide what you're building: an orchestration layer, or a growing collection of provider exceptions. Most teams don't decide. They accumulate.

Eachlabs is a developer-first platform for running image, video and audio jobs through one backend: one key, one request envelope, and workflows that chain models into a single production endpoint. This piece is about the four things that actually make that worth having: how requests get routed, how model selection can be a rule rather than a preference, what production readiness means concretely, and how multi-step media chains hold together when a step breaks.

One backend, three modalities, one request shape

Start with the mechanical part, because it's the foundation everything else sits on.

Every model on the platform (image, video, audio, text) takes the same envelope. A slug, a version, and an input object, POSTed to one URL:

curl -X POST https://api.eachlabs.ai/v1/prediction/ \
  -H "Authorization: Bearer $EACHLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-flash-text-to-image",
    "version": "0.0.1",
    "input": { "prompt": "...", "image_size": "landscape_16_9" },
    "webhook_url": ""
  }'

Change the slug to sora-2-text-to-video and you're generating video. Change it again and you're generating audio. The auth header doesn't move, the response envelope doesn't move, and the code that consumes the result doesn't move.

That sounds like a modest convenience. It's the whole thing. The cost of integrating a model is not the first call. It's every line of code downstream that knows what that particular vendor's response looks like. Normalise the envelope and swapping a model becomes a string change. Don't, and "we'll evaluate the new model next sprint" becomes a sentence you say for a year.

Predictions are asynchronous by design. You submit, get a prediction ID, and either poll GET /v1/prediction/{id} or pass a webhook_url. Six states (created, starting, processing, then success, error or cancelled), with metrics.predict_time on the terminal response telling you what the run actually took. Alongside that, the LLM Router exposes an OpenAI-compatible surface for text and audio on the same base URL, which means an existing OpenAI-compatible client can point at it without a rewrite.

Routing is a switch, not a preference.
Routing is a switch, not a preference.

Make model selection a rule, not a preference

Here's the question worth sitting with: when your system picks a model, is that a decision your code makes, or a decision someone made once in a config file and nobody has revisited since?

Most "model routing" in the wild is the second thing. A constant, set during a spike, defended by inertia. Real routing means the choice is derived from the request.

Three routing rules cover almost everything in practice.

Route on task shape. The most valuable and least glamorous rule. A prompt with no source image goes to text-to-image. A prompt with a source goes to an edit endpoint. A source plus a target aspect ratio goes to a reference-conditioned model. Getting this wrong is the most common cause of mediocre output, and it's not a model problem, it's a dispatch problem. Editing an existing image with a text-to-image endpoint produces something plausible that isn't your product.

Route to the lightest model that clears the bar. Not the best model. The lightest sufficient one. Model families are built as ladders precisely so you can do this. The FLUX.2 line runs from the distilled klein variants through flash and turbo up to flux-2-max-text-to-image, and they take the same parameters. So: thumbnails and internal previews go to the light end, hero assets go to the top, and the tier is a function of what the asset is for rather than a global default. Teams that skip this run every request at maximum fidelity and then wonder why the nightly batch doesn't finish.

Route around failure. Define a fallback per capability, not per model. If the primary image endpoint returns a terminal error, the next call goes to a declared alternate that produces a compatible output with the same shape and the same downstream consumer. This is the rule that turns a vendor incident from an outage into a latency bump. The LLM Router does this natively for text; for media, you declare it in your workflow graph.

What routing does not do (and I want to be precise, because this is oversold across the industry) is pick the right model for your taste. There is no automatic router that knows your brand looks better on one image model than another. Routing dispatches on properties your code can observe: task shape, target quality tier, prior failure. Aesthetic fit is still an evaluation you run yourself, on your prompts, at your volume. The platform's job is to make re-running that evaluation cost an afternoon instead of a sprint.

The right model is the lightest one that still clears the bar.
The right model is the lightest one that still clears the bar.

What production readiness actually means here

Every platform claims to be production-ready. Ask for the specifics and the conversation usually gets vague, so here are the specifics that matter, all of them observable.

Credentials. API keys are accepted only as Authorization: Bearer. Query-string keys are rejected outright, so credentials can't leak into URLs, access logs, or a referrer header. That's a small design decision that tells you something about who built the contract. You only make that choice after you've cleaned up an incident caused by the alternative.

Version pinning where it counts. Predictions take an explicit version in the request body. Workflows go further: POST /v1/workflows/trigger/{workflowID}/{versionID} puts the version in the path, not inferred from "latest." That means someone editing a workflow in the dashboard cannot silently change what production is running. If you have ever debugged an output that changed with no deploy, you know exactly why this matters.

Error semantics you can act on. Distinct statuses for distinct problems: 400 for an invalid request, returned before any provider work starts so nothing is spent; 401 for a bad token; 402 when the account can't fund the run; 404 for a capability that isn't enabled; 413 for oversized input; 429 for concurrency; 503 and 504 for upstream trouble. The 429 case deserves attention because it's routinely mishandled, it's an account concurrency cap rather than a per-second rate limit, the details field always names the cap that applied, and a rejected request creates no prediction at all. So it's a resubmit path, not a failure path. Conflating the two is how a batch job quietly loses work.

Observability per request. Every prediction carries a durable ID, a terminal status, metrics.predict_time, and logs where the model emits them. Workflow executions are readable individually via GET /v1/workflows/executions/{executionID} and listable per workflow. Webhook deliveries, including attempts, are inspectable by execution ID. That combination is what lets you answer "why does this one asset look wrong" six weeks later. Provided you stored the prediction ID next to the asset, which is the one piece only you can do.

Delivery you can trust. Webhooks use a compact two-value vocabulary (succeeded or failed) distinct from the six-state polling lifecycle, so don't share a parser between them. And you may receive the same webhook more than once, which means the handler must be idempotent, keyed on the prediction ID. Both are trivial on day one and genuinely painful to retrofit after duplicate deliveries have overwritten good assets.

Input handling. Your own media goes in through each::storage, which returns a public URL, the shape every model expects, since edit and reference endpoints take images and audio by URL rather than multipart. Deletes are idempotent, which matters for retention jobs.

What this doesn't give you: it isn't a compliance certificate, and it doesn't decide your data-retention policy. Generated assets and uploaded inputs live somewhere, and if you operate under constraints about where customer media may sit, that's a question to settle explicitly before you build the pipeline rather than after legal reads the architecture doc. An orchestration layer removes integration risk. It doesn't remove governance work.

Production readiness is who may call what, and what got written down.
Production readiness is who may call what, and what got written down.

Chaining steps, and surviving the one that breaks

The reason routing and orchestration belong in the same conversation is that real media work is never one call.

Take a product video generated from a single photograph. Isolate the product with eachlabs-bg-remover-v1. Composite it into a scene with an edit endpoint like flux-2-max-edit or nano-banana-2-edit. The latter takes an array of image_urls, up to ten, so you can condition on both product and style reference. Animate the result with sora-2-image-to-video, where image_url is required and duration comes from a fixed set of 4, 8, 12, 16 or 20 seconds. Generate narration. Then, if there's a face in frame, drive the mouth with sync-3-lipsync, which takes a video_url and an audio_url.

Five steps. Each one can fail independently, at a different latency, and each one's output is the next one's input.

Write that in application code and you have built a workflow engine with none of the properties of one: no version pinning, no execution history, no way to rerun step four without redoing steps one through three. Declare it as a workflow instead and you get a graph you can version, trigger, inspect and hand to a colleague. Executions report running, completed, failed or cancelled, and there's a bulk trigger route for queueing many executions of the same pinned version in one call.

Two rules make chains survivable, and they're both about intermediates.

Store every intermediate. The matte from step one, the composite from step two, the clip from step three. Not for archival tidiness. It's what makes a retry possible.

Retry the step, not the chain. This is the rule people learn the hard way. Re-running a generative step does not reproduce it; it produces something new. So if lip-sync fails and your retry logic re-runs the whole pipeline, you don't get your video back with the mouth fixed. You get a different video, with a different composite, possibly a different product angle. In an avatar pipeline, a different face. Idempotency in generative systems means holding artifacts, not repeating work.

Get those two right and a broken step is a bypass. Get them wrong and a broken step is a full regeneration, which is both slower and non-deterministic in a way that will eventually ship to a customer.

A chain is only as good as its route around the broken step.
A chain is only as good as its route around the broken step.

Choosing: match the need to the capability

Plainly, without a matrix.

If you need one model for one task, forever, a focused single-purpose tool is less to reason about, and you should use it. I'd rather say that than pretend every problem needs a platform. The threshold is the second step and the second modality. That's where per-vendor integration starts costing more than it saves.

If you need multiple modalities behind one backend (image and video and audio in the same product), the argument for a single envelope is straightforward: you write the submit-and-poll logic once and every new capability is a slug.

If you need quality tiers, because previews and hero assets have genuinely different requirements, you want families built as ladders and a dispatch rule that picks the tier from the request. Running everything at maximum fidelity is the most common and most expensive mistake in this category.

If you need multi-step chains, you want workflows with the version pinned in the path, stored intermediates, and per-step retry. This is the case where doing it yourself is most tempting and least advisable, because the engine you'd write is the one part of the system with no product value.

If you need failure to be boring, you want declared fallbacks per capability, error statuses distinct enough to route on, durable prediction IDs, and idempotent webhook handling. Reliability here isn't uptime. It's that a vendor having a bad afternoon shows up in your latency graph rather than your incident channel.

And if what you need is a specific model, right now, evaluated properly against your own prompts, that's still your work. The platform makes it fast to run and fast to redo. It doesn't make the judgement for you, and any claim otherwise is selling something.

If you're maintaining a switch statement over vendors, that's the thing worth replacing. Start with one endpoint on Eachlabs and put the chain behind it.