The Problem With Wiring Providers Directly
The moment your app needs more than one model — say GPT Image 2 for hero art, Seedance for video, and a cheap LLM for captions — the naive path means three SDKs, three sets of credentials, three billing dashboards, three response formats, and three failure modes. Every new model is another integration. This guide lays out the architecture that avoids that: route everything through one gateway so a model is just a string.
The Gateway Pattern
Instead of importing each provider's SDK, point one HTTP client at a gateway that speaks to all of them. Model selection becomes a parameter, not a code path. On LinkModel, a single key and one request schema cover 40+ image and video models; switching models in production is changing one string.
import os, time, requests
BASE = "https://api.linkmodel.ai/api/v1"
H = {"Authorization": f"Bearer {os.environ['LINKMODEL_API_KEY']}",
"Content-Type": "application/json"}
def submit(endpoint, model, prompt, **extra):
body = {"model": model, "prompt": prompt, **extra}
r = requests.post(f"{BASE}/{endpoint}", headers=H, json=body).json()
if r["code"] != 0:
raise RuntimeError(r["msg"])
return r["data"]["task_id"]Handle the Async Task Lifecycle Once
Generation models are asynchronous: submit, get a task_id, poll for the result. Write that loop a single time and reuse it for every model:
def wait(endpoint, task_id, interval=3, timeout=600):
start = time.time()
while time.time() - start < timeout:
q = requests.get(f"{BASE}/query/{endpoint}",
headers=H, params={"task_id": task_id}).json()
status = q["data"]["status"]
if status == "completed":
return q["data"]
if status == "failed":
raise RuntimeError("generation failed")
time.sleep(interval)
raise TimeoutError(task_id)
def run(endpoint, model, prompt, **extra):
return wait(endpoint, submit(endpoint, model, prompt, **extra), )Now your whole app calls run("image-generation", "gpt-image-2", prompt) or run("video-generation", "seedance-2-0", prompt) — same code, any model.
Route by Task, Not by Habit
With switching this cheap, route each job to the right-cost model. Draft on a fast/cheap tier, finish on a premium one; pick 4K only when the deliverable needs it.
def make_video(prompt, final=False, fourk=False):
if fourk:
model = "kling-v3" # native 4K master
elif final:
model = "seedance-2-0" # best value premium
else:
model = "seedance-2-0" # (use the Fast/Mini tier for drafts)
return run("video-generation", model, prompt)This is the same principle that drives most AI cost savings — see how to reduce AI API costs.
Build In Fallbacks
Any single model can be slow, rate-limited, or (like Sora 2, sunsetting Sept 2026) go away entirely. A gateway makes fallback trivial — try one model, catch, try the next:
def resilient_video(prompt, order=("seedance-2-0", "kling-v3")):
last = None
for model in order:
try:
return run("video-generation", model, prompt)
except Exception as e:
last = e
raise lastBecause the request shape is identical across models, your fallback list is just an array of strings.
What You Get From This Architecture
- One credential, one bill — no per-provider account sprawl.
- Model-by-parameter — add or swap models without new integrations.
- Uniform response + task handling — write the polling and error logic once.
- Predictable cost — fixed per-request pricing (up to 30% below official on LinkModel) instead of juggling per-GPU-second variance; contrast in LinkModel vs fal.ai.
- Future-proofing — when a better model ships, it's a one-line change.
Picking the Models
Use the roundups to choose what to route to: best AI image generation APIs, best AI video generation APIs, and the AI API pricing comparison.
Get one key with a $1 credit and wire the gateway pattern in an afternoon. Full schema at docs.linkmodel.ai.
