I've been using OpenRouter for about a year. For pure LLM work it's hard to beat: one API key, OpenAI-compatible, access to GPT, Claude, Gemini, DeepSeek, and a hundred others. You write the code once and swap models by changing a string.
Then I started a project that needed image generation alongside the LLM calls. Specifically, Midjourney — a client requirement. OpenRouter doesn't have it. Most platforms don't, actually. So I ended up with two separate API integrations, two billing accounts, and two sets of credentials to manage.
That's when I started looking at CometAPI.
What OpenRouter does well
To be clear: OpenRouter is genuinely good at what it does.
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="YOUR_OPENROUTER_KEY"
)
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4-5",
messages=[{"role": "user", "content": "Summarize this in 3 bullet points."}]
)
print(response.choices[0].message.content)
That's it. No SDK changes, no new patterns to learn. If you're already using the OpenAI Python SDK, you're done. OpenRouter's model coverage for LLMs is excellent — 200+ models from every major provider.
The problem is that it stops there. No image generation. No video generation. No Midjourney.
The two-API problem
For a while I ran OpenRouter for LLM calls and a separate service for image generation. This works, but it creates friction:
- Two API keys to rotate and store securely
- Two billing dashboards to monitor
- Two rate limit systems to handle
- Different error formats to normalize
- Different retry logic for each
For a side project this is annoying. For a production system with multiple team members, it becomes a real maintenance burden.
Switching to CometAPI
CometAPI is structured differently. It covers LLMs (500+ models), image generation (Midjourney, Flux, GPT Image 2, DALL-E 3 legacy, Bria, Seedream), and video generation (Kling, Veo 3, Runway, Wan, Sora 2) — all under one API key and one OpenAI-compatible endpoint.
The migration for LLM calls was literally two lines:
from openai import OpenAI
# Before (OpenRouter)
# client = OpenAI(
# base_url="https://openrouter.ai/api/v1",
# api_key="YOUR_OPENROUTER_KEY"
# )
# After (CometAPI) — everything else stays the same
client = OpenAI(
base_url="https://api.cometapi.com/v1",
api_key="YOUR_COMETAPI_KEY"
)
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=[{"role": "user", "content": "Summarize this in 3 bullet points."}]
)
print(response.choices[0].message.content)
No new SDK. No structural changes. The rest of my codebase didn't need to be touched.
Adding Midjourney to the same project
This is the part that actually solved my original problem. CometAPI provides Midjourney API access — something OpenRouter doesn't offer and most platforms have removed or never had.
import requests
import time
API_KEY = "YOUR_COMETAPI_KEY"
BASE = "https://api.cometapi.com"
def generate_midjourney(prompt: str, mode: str = "mj-fast") -> dict:
"""
mode options:
"mj-fast" — $0.056/task
"mj-turbo" — $0.168/task (~3x faster)
"""
# Step 1: Submit the task
r = requests.post(
f"{BASE}/{mode}/mj/submit/imagine",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={"prompt": prompt}
)
r.raise_for_status()
task_id = r.json()["result"]
print(f"Task submitted: {task_id}")
# Step 2: Poll for result
for attempt in range(30):
time.sleep(10)
result = requests.get(
f"{BASE}/mj/task/{task_id}/fetch",
headers={"Authorization": f"Bearer {API_KEY}"}
)
data = result.json()
status = data.get("status")
print(f" [{attempt+1}] Status: {status}")
if status == "SUCCESS":
return data
elif status in ("FAILURE", "CANCELLED"):
raise RuntimeError(f"Task failed: {data}")
raise TimeoutError("Task did not complete in time")
# Usage
result = generate_midjourney(
"a photorealistic mountain landscape at sunrise, "
"cinematic lighting --ar 16:9 --v 7"
)
print("Image URL:", result.get("imageUrl"))
The same API key that handles my Claude and GPT calls now handles Midjourney. One credential, one billing account.
Pricing comparison
Both platforms publish pricing publicly — you shouldn't have to sign up to estimate costs.
| Model | OpenRouter | CometAPI |
|---|---|---|
| GPT-4o (per 1M tokens) | $2.50 in / $10.00 out | $2.00 in / $8.00 out |
| Claude Sonnet 4.5 (per 1M tokens) | $3.00 in / $15.00 out | $2.40 in / $12.00 out |
| Gemini 2.5 Pro (per 1M tokens) | $1.25 in / $10.00 out | $1.00 in / $8.00 out |
| DeepSeek V3 (per 1M tokens) | $0.14 in / $0.28 out | $0.11 in / $0.22 out |
| Midjourney Fast (per task) | ❌ Not available | $0.056 |
| Midjourney Turbo (per task) | ❌ Not available | $0.168 |
| Flux 2 MAX (per image) | ❌ Not available | $0.008 |
| GPT Image 1 low (per image) | ❌ Not available | $0.009 |
| Veo 3 video (per second) | ❌ Not available | Available |
CometAPI applies a ~20% discount across most models relative to official provider rates. For LLMs the saving is real but modest — the bigger difference is the image and video coverage that OpenRouter simply does not have. Prices verified May 2026 from openrouter.ai/models and cometapi.com/pricing.
What I actually use now
My current setup for the multimodal project:
from openai import OpenAI
import requests
import time
client = OpenAI(
base_url="https://api.cometapi.com/v1",
api_key="YOUR_COMETAPI_KEY"
)
def analyze_brief(brief: str) -> str:
"""Use Claude to extract key visual requirements from a creative brief."""
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=[{
"role": "user",
"content": (
"Extract the key visual elements from this brief "
"as a Midjourney prompt:\n\n" + brief
)
}]
)
return response.choices[0].message.content
def generate_image(prompt: str) -> str:
"""Generate image via Midjourney and return the URL."""
r = requests.post(
"https://api.cometapi.com/mj-fast/mj/submit/imagine",
headers={
"Authorization": "Bearer YOUR_COMETAPI_KEY",
"Content-Type": "application/json"
},
json={"prompt": prompt}
)
task_id = r.json()["result"]
for _ in range(30):
time.sleep(10)
result = requests.get(
f"https://api.cometapi.com/mj/task/{task_id}/fetch",
headers={"Authorization": "Bearer YOUR_COMETAPI_KEY"}
).json()
if result.get("status") == "SUCCESS":
return result["imageUrl"]
raise TimeoutError("Generation timed out")
# Pipeline: brief -> LLM prompt extraction -> Midjourney image
brief = "A luxury watch campaign. Dark, moody. The watch face should be the hero."
mj_prompt = analyze_brief(brief)
print("Generated prompt:", mj_prompt)
image_url = generate_image(mj_prompt + " --ar 3:2 --v 7")
print("Image:", image_url)
One API key. One billing account. LLM and image generation in the same script.
When to stick with OpenRouter
OpenRouter is still the better choice if:
- Your project is purely LLM — no image or video generation needed
- You need specific models that OpenRouter carries but CometAPI doesn't
- You're already integrated and the migration cost isn't worth it for your use case
OpenRouter's model breadth for LLMs is genuinely impressive, and their routing infrastructure is solid. If you don't need multimodal, there's no strong reason to switch.
TL;DR
- OpenRouter = excellent LLM router, 200+ models, no image/video generation
- CometAPI = LLM + image + video under one API key, OpenAI-compatible, includes Midjourney
If your project only calls LLMs, OpenRouter is fine. If you need image or video generation alongside LLM calls — especially Midjourney — CometAPI eliminates the two-API problem.
Free trial at cometapi.com — no credit card required.
Top comments (0)