Magnific
Magnific generative-media API (api.magnific.com, part of Freepik) — image generation, upscaling, video, audio, and stock content through one async task API. Use when calling Magnific or working with any of its models — Mystic; Flux (2 Pro / 2 Turbo / 2 Klein / Dev / Kontext Pro / Pro v1.1 / HyperFlux); Seedream 4 / 4.5 / 4.5 Edit; Z-Image; the Creative & Precision Upscalers; Relight; Style Transfer; Remove Background; Image Expand; Kling 2.1/2.5/2.6/O1/Motion-Control; MiniMax Hailuo & Video-01-Live; WAN 2.5/2.6; Runway Gen4 Turbo & Act-Two; LTX 2.0 Pro; Seedance; PixVerse; OmniHuman; VFX; music generation; sound effects; audio isolation; or the team analytics + stock (icons / videos / templates) endpoints. Triggers — "Magnific API", "x-magnific-api-key", "upscale an image", "image to video", "generate an image/video/music", "poll a task_id", "Magnific webhook signature", "Magnific MCP". Covers the submit→poll-or-webhook task model, auth, webhook HMAC verification, rate limits, pricing, and the full per-endpoint catalog in references/. Do NOT use for non-Magnific image tools, the generic OpenAI/Anthropic SDKs, or unrelated Freepik stock APIs.From its SKILL.md
npx -y skills add andreab67/agent-skills --skill magnificAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
20.9 KB, ~5.6k tokens by cl100k_base, as published. Nobody here has run it
magnific
Magnific is a generative-media API (image, video, audio, and stock content) served at https://api.magnific.com/v1. Almost every generation endpoint works the same way: you submit a job, get back a task_id, then either poll a GET endpoint or let a webhook deliver the result. Learn that one rhythm and the other ~60 endpoints are just different request bodies.
This skill is the operating manual. The exhaustive, per-endpoint parameter/request/response detail for every model lives in references/ — reach for it when you need an exact enum value or field name.
When to use
- Building anything against
api.magnific.com— generating, editing, upscaling images; making video/music/SFX; pulling stock assets. - Choosing the right Magnific model for a task ("which model upscales while inventing detail?", "fastest text-to-image?", "image-to-video from a still?").
- Wiring up the async lifecycle: submitting jobs, polling
task_id, or receiving + verifying webhooks. - Debugging a 401/400, an empty
generatedarray, a job stuckIN_PROGRESS, or a webhook signature mismatch.
Do NOT use for
- Non-Magnific image/video tools (Replicate, fal, raw Stability/RunwayML APIs), or the generic OpenAI/Anthropic SDKs — those have their own skills.
- The separate Freepik stock-photo API. Magnific's stock endpoints (
/v1/resources,/v1/icons,/v1/videos) are covered here; the standalone Freepik API is not.
The one mental model: submit → poll or webhook
99% of Magnific endpoints are asynchronous. A POST does not return your image/video — it returns a
task_id. The result arrives later.
POST /v1/ai/<model> → 202-ish: { "data": { "task_id": "…", "status": "CREATED", "generated": [] } }
│
├── (a) POLL: GET /v1/ai/<model>/{task_id} every few seconds until status == COMPLETED
│
└── (b) WEBHOOK: pass "webhook_url" in the POST → Magnific POSTs the same payload to you on each status change
- Status enum (every task, every model):
CREATED→IN_PROGRESS→COMPLETED|FAILED. generatedis an empty array[]untilstatus == "COMPLETED", then it holds the output URL(s).- Production rule: always pass a
webhook_url. Polling is fine for scripts/notebooks; webhooks are how you avoid hammering the API (and the rate limits) in a real app. Video/music jobs can take minutes — do not tight-poll them. - Two documented exceptions to the async model (don't poll these):
- Remove Background (
POST /v1/ai/beta/remove-background) is synchronous — it returns image URLs directly, notask_id. - Style Transfer returns
task_status(notstatus) and is not wrapped indatain the docs — parse both shapes defensively.
- Remove Background (
Quick start
Auth. Every request carries your key in the x-magnific-api-key header (note: not Authorization: Bearer). Keys are server-to-server only — never ship one to a browser/mobile client. Generate keys at magnific.com → Settings → Organization → API Keys (admin role required).
# Submit a Mystic image generation
curl -X POST https://api.magnific.com/v1/ai/mystic \
-H "x-magnific-api-key: $MAGNIFIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a cat with wings playing a guitar, cinematic lighting",
"resolution": "2k",
"aspect_ratio": "widescreen_16_9",
"model": "realism",
"webhook_url": "https://your-app.com/webhooks/magnific"
}'
# → { "data": { "task_id": "046b6c7f-…", "status": "CREATED", "generated": [] } }
# Poll for the result
curl https://api.magnific.com/v1/ai/mystic/046b6c7f-… \
-H "x-magnific-api-key: $MAGNIFIC_API_KEY"
# → { "data": { "task_id": "046b6c7f-…", "status": "COMPLETED",
# "generated": ["https://ai-statics.freepik.com/…jpg"], "has_nsfw": [false] } }
Python — submit + poll, the right way
import os, time, requests
BASE = "https://api.magnific.com/v1"
HEADERS = {"x-magnific-api-key": os.environ["MAGNIFIC_API_KEY"]}
def submit(model_path: str, body: dict) -> str:
r = requests.post(f"{BASE}/ai/{model_path}", headers=HEADERS, json=body, timeout=30)
r.raise_for_status()
return r.json()["data"]["task_id"]
def wait(model_path: str, task_id: str, *, interval=3, timeout=600) -> list[str]:
"""Poll until COMPLETED. Returns the `generated` URLs. Raises on FAILED/timeout."""
deadline = time.time() + timeout
while time.time() < deadline:
r = requests.get(f"{BASE}/ai/{model_path}/{task_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
data = r.json()["data"]
status = data.get("status") or data.get("task_status") # Style Transfer uses task_status
if status == "COMPLETED":
return data["generated"]
if status == "FAILED":
raise RuntimeError(f"task {task_id} FAILED")
time.sleep(interval)
raise TimeoutError(f"task {task_id} not done after {timeout}s")
task = submit("mystic", {"prompt": "a serene alpine lake at dawn", "resolution": "2k"})
print(wait("mystic", task))
TypeScript — submit
const BASE = "https://api.magnific.com/v1";
const res = await fetch(`${BASE}/ai/image-upscaler`, {
method: "POST",
headers: {
"x-magnific-api-key": process.env.MAGNIFIC_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({ image: base64Image, scale_factor: "4x", engine: "magnific_sparkle" }),
});
const { data } = await res.json(); // { task_id, status, generated: [] }
Model catalog
Pick by intent. Full param tables for each are in references/. Paths below are relative to https://api.magnific.com/v1.
Image generation — text-to-image (references/image-generation.md)
| Model | POST path | Reach for it when… |
|---|---|---|
| Mystic ⭐ | /ai/mystic | The flagship. Photoreal and illustration; structure/style reference images, @character mentions, style/color steering. model: realism/super_real/zen/flexible/fluid/editorial_portraits. resolution 1k/2k/4k. |
| Flux 2 Pro | /ai/text-to-image/flux-2-pro | High fidelity + up to 4 base64 input images for multi-image conditioning. ≤1440px (width/height). |
| Flux 2 Turbo | /ai/text-to-image/flux-2-turbo | Fast. Square/rect up to 2048px via image_size:{width,height}. guidance_scale 1–20, enable_safety_checker. |
| Flux 2 Klein | /ai/text-to-image/flux-2-klein | Aspect-ratio + 1k/2k, up to 4 reference images, safety_tolerance 0–5. |
| Flux Kontext Pro | /ai/text-to-image/flux-kontext-pro | Reference-guided edits with guidance/steps dials. input_image is a URL (not base64). |
| Flux Pro v1.1 | /ai/text-to-image/flux-pro-v1-1 | Prior-gen production model, safety_tolerance 0–6. |
| Flux Dev | /ai/text-to-image/flux-dev | Rich styling — effects (color/framing/lightning) + dominant-color palette. Prompt optional. |
| HyperFlux | /ai/text-to-image/hyperflux | Fastest/cheapest Flux; same styling palette as Flux Dev. |
| Runway | /ai/text-to-image/runway | Runway t2i. ratio is required and uses literal pixel strings (1920:1080, …) — not aspect names. |
| Seedream 4 / 4.5 | /ai/text-to-image/seedream-v4 · seedream-v4-5 | ByteDance Seedream. |
| Seedream 4.5 Edit | /ai/text-to-image/seedream-v4-5-edit | Edit an existing image with Seedream 4.5. |
| Z-Image Turbo | /ai/text-to-image/z-image | Fast lightweight text-to-image. |
Image editing (references/image-editing.md)
| Model | POST path | Reach for it when… |
|---|---|---|
| Upscaler — Creative ⭐ | /ai/image-upscaler | Enlarge and invent detail (prompt-guided). scale_factor 2x/4x/8x/16x; creativity/hdr/resemblance/fractality each -10..10; optimized_for presets. Output ≤ 25.3 MP. |
| Upscaler — Precision | /ai/image-upscaler-precision | Enlarge faithfully (no reinterpretation). sharpen/smart_grain/ultra_detail 0..100. |
| Relight | /ai/image-relight | Change lighting via prompt, reference image, or lightmap (the latter two are mutually exclusive). ~€0.10/op. |
| Style Transfer | /ai/image-style-transfer | Repaint an image in a reference's style. ⚠ returns task_status, not wrapped in data. ~€0.10/op. |
| Remove Background | /ai/beta/remove-background | Cutout. Synchronous, form-encoded body, result URLs expire in 5 min. |
| Image Expand | /ai/image-expand/flux-pro | Outpaint/extend canvas. left/right/top/bottom px, each 0..2048. |
Video generation (references/video-generation.md)
| Family | Models (POST paths under /ai/) |
|---|---|
| Kling | image-to-video/kling-v2-1-pro · kling-v2-5-pro · kling-v2-6-pro (text or image) · kling-o1-pro (first/last frame) · video/kling-v2-6-motion-control-pro |
| MiniMax | image-to-video/minimax-hailuo-02-1080p · minimax-hailuo-2-3-1080p · minimax-live (Video-01-Live) |
| WAN | text-to-video/wan-2-5-t2v-1080p · image-to-video/wan-2-5-i2v-1080p · wan-v2-6-1080p |
| Runway | image-to-video/runway-gen4-turbo · video/runway-act-two |
| Others | text-to-video/ltx-2-pro · image-to-video/seedance-pro-1080p · image-to-video/pixverse-v5 · video/omni-human-1-5 · video/vfx |
Audio (references/audio.md)
| Capability | Endpoints (under /ai/) |
|---|---|
| Music generation | POST music-generation · GET music-generation (list) · GET music-generation/{task-id} |
| Sound effects | POST sound-effects · GET sound-effects · GET sound-effects/{task-id} |
| Audio isolation | POST audio-isolation · GET audio-isolation · GET audio-isolation/{task-id} |
Analytics & stock content (references/analytics-and-stock.md)
| Capability | Endpoints (under /v1/) |
|---|---|
| Team analytics | POST analytics/team-credit-usage · GET analytics/team-members · team-api-keys · team-groups · team-projects. Business/Enterprise only; consume no credits; 100 req/day. |
| Stock — images & templates | GET resources · resources/{id} · resources/{id}/download · resources/{id}/download/{format} |
| Stock — icons | GET icons · icons/{id} · icons/{id}/download |
| Stock — videos | GET videos · videos/{id} · videos/{id}/download |
Copy-paste recipes
Upscale an image (the flagship), end-to-end
import base64, requests, os
HEADERS = {"x-magnific-api-key": os.environ["MAGNIFIC_API_KEY"]}
with open("input.jpg", "rb") as f:
img_b64 = base64.b64encode(f.read()).decode()
body = {
"image": img_b64,
"scale_factor": "4x", # 2x | 4x | 8x | 16x — output must stay ≤ 25.3 MP
"optimized_for": "films_n_photography",
"prompt": "ultra-detailed, sharp, photorealistic",
"creativity": 2, # -10..10 (how much new detail AI may invent)
"hdr": 1, # -10..10
"resemblance": 0, # -10..10 (fidelity to the original)
"fractality": -1, # -10..10 (prompt strength / detail-per-pixel)
"engine": "magnific_sparkle", # automatic | magnific_illusio | magnific_sharpy | magnific_sparkle
}
task_id = requests.post("https://api.magnific.com/v1/ai/image-upscaler",
headers=HEADERS, json=body, timeout=60).json()["data"]["task_id"]
# then poll GET /v1/ai/image-upscaler/{task_id} (see wait() helper above)
Creative vs Precision: use
image-upscaler(Creative) when you want the AI to add detail/texture; useimage-upscaler-precisionwhen the output must stay faithful to the source (no hallucinated detail) — it exposes onlysharpen/smart_grain/ultra_detail.
Image-to-video (Kling)
# Most i2v models take a base64/URL `image` + `prompt`; see references/video-generation.md
# for each model's exact params (duration, aspect, cfg, etc.). Always use a webhook for video.
body = {"image": img_b64, "prompt": "slow cinematic push-in, gentle camera motion",
"webhook_url": "https://your-app.com/webhooks/magnific"}
task_id = requests.post("https://api.magnific.com/v1/ai/image-to-video/kling-v2-6-pro",
headers=HEADERS, json=body, timeout=60).json()["data"]["task_id"]
Receive + verify a webhook (Svix-style HMAC-SHA256)
Magnific signs webhooks the way Svix does. Each delivery carries three headers — webhook-id, webhook-timestamp, webhook-signature — and you verify by HMAC-ing "{id}.{timestamp}.{raw_body}". Get the signing secret from the dashboard (magnific.com/user/organization/api-keys). Always verify against the raw request body, before any JSON parsing.
import hmac, hashlib, base64
def verify_magnific_webhook(secret: str, headers: dict, raw_body: bytes) -> bool:
wid = headers["webhook-id"]
wts = headers["webhook-timestamp"]
signed = f"{wid}.{wts}.{raw_body.decode()}".encode()
# Svix secrets are usually base64 (sometimes prefixed "whsec_"); decode if so.
key = secret.split("_", 1)[1] if secret.startswith("whsec_") else secret
try:
key_bytes = base64.b64decode(key)
except Exception:
key_bytes = key.encode()
expected = base64.b64encode(hmac.new(key_bytes, signed, hashlib.sha256).digest()).decode()
# webhook-signature is space-delimited, each entry "v1,<base64sig>"
for part in headers["webhook-signature"].split(" "):
sig = part.split(",", 1)[1] if "," in part else part
if hmac.compare_digest(sig, expected):
return True
return False
// Node — same scheme
import crypto from "node:crypto";
export function verify(secret, headers, rawBody) {
const signed = `${headers["webhook-id"]}.${headers["webhook-timestamp"]}.${rawBody}`;
const key = secret.startsWith("whsec_") ? secret.slice(6) : secret;
const keyBuf = Buffer.from(key, "base64");
const expected = crypto.createHmac("sha256", keyBuf).update(signed).digest("base64");
return headers["webhook-signature"].split(" ").some((p) => {
const sig = p.includes(",") ? p.split(",")[1] : p;
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
});
}
The webhook payload mirrors the GET-status response without the outer data wrapper — i.e. { "task_id", "status", "generated", ... }. Use the task_id to match it to the job you submitted.
Pre-flight checklist
Before you call any generation endpoint:
- Key in the right header —
x-magnific-api-key, server-side only. (NotAuthorization.) - Right base URL —
https://api.magnific.com/v1, and the/ai/segment for generation paths. - Expect a
task_id, not a result — wire up polling or awebhook_urlbefore you ship. Decide which per call (webhook for prod, poll for scripts). - Image inputs: check base64-vs-URL per model (e.g. Flux 2 Pro/Klein = base64; Flux Kontext Pro = URL; Relight/Style Transfer accept either). Send the original file, not a
canvas.toDataURL()re-encode (loses ~8–20% quality). - Upscaler: confirm
input_pixels × scale_factor²stays under 25.3 MP or the job rejects. - NSFW defaults differ: Mystic's
filter_nsfwdefaultstrueand cannot be disabled on standard accounts; the upscalers defaultfalse. Don't assume. - Vocabulary per model: aspect ratios are named enums (
widescreen_16_9) on most models — but Runway uses literal pixelratiostrings, and Flux 2 Turbo uses animage_sizeobject. The effect key in Flux Dev/HyperFlux is spelledlightning, not "lighting".
Anti-patterns — looks right, isn't
- Reading the image URL off the POST response. The POST returns
{task_id, status:"CREATED", generated:[]}—generatedis empty. The URL only exists after the task reachesCOMPLETED. Poll or webhook for it. Authorization: Bearer <key>. Wrong header. Magnific usesx-magnific-api-key. ABearertoken yields401.- Tight-polling a video/music job every 200ms. Those run for minutes and you'll trip the rate limits (50 req/min). Use a webhook, or poll every few seconds.
- Assuming every response is
{ "data": { "status": … } }. Style Transfer returnstask_statusand is not wrapped indata; Remove Background returns image URLs synchronously with no task at all. Parse defensively (thewait()helper above does). - Polling Remove Background for a
task_id. It's synchronous — there is no task. The returned URLs also expire in 5 minutes; download immediately. - Putting the API key in a browser/mobile app. Keys are server-to-server only. Proxy generation calls through your backend.
- Expecting LoRAs to apply to any Mystic config. Mystic silently ignores LoRAs (no error) when using
fluid/flexible/super_real/editorial_portraits, or whenever astructure_reference/style_referenceis supplied. - Trying to disable Mystic's NSFW filter.
filter_nsfw:falseis rejected on standard accounts — only specially-authorized clients can turn it off. - Skipping webhook signature verification (or verifying against the parsed/re-serialized JSON). Verify the HMAC over the raw body, or you'll accept spoofed callbacks and reject legitimate ones.
Rate limits
Documented limits (no 429/limit-header names are published — back off on errors regardless):
- 50 requests/minute overall.
- Burst: 50 hits/sec over a 5-second window, and 10 hits/sec averaged over 2 minutes.
- 1,000 requests/day on
ai-image-to-prompt,ai-improve-prompt,ai-powered-search. - 100 requests/day on Analytics endpoints (Business/Enterprise only; no credit cost).
Pricing (credit model)
Usage is credit-based, deducted from the org balance per call. The web-app "Unlimited" plan does not cover API usage. Few per-call numbers are published; the ones the docs state: Relight and Style Transfer ≈ €0.10/operation; upscales ≈ €0.10–€0.50 depending on output pixel area (input dims × scale factor). For image/video generation, cost scales with resolution/megapixels ("higher resolution = higher cost"). Treat any figure beyond those as "not documented — verify on the pricing page."
MCP server
Magnific ships a hosted Model Context Protocol server at https://mcp.magnific.com, authenticated via OAuth 2.0 (no API key). It lets an AI assistant (Claude, etc.) drive Magnific generation as tools. Use it for assistant-driven workflows; use the REST API above for programmatic/backend integration.
Reference files
Exhaustive, verbatim per-endpoint detail (every parameter, enum, default, request/response example, and gotcha) for all ~60 endpoints:
references/image-generation.md— Mystic, Flux family, Seedream, Z-Image, Runway t2ireferences/image-editing.md— Upscalers, Relight, Style Transfer, Remove BG, Expandreferences/video-generation.md— Kling, MiniMax, WAN, Runway, LTX, Seedance, PixVerse, OmniHuman, VFXreferences/audio.md— music, sound effects, audio isolationreferences/analytics-and-stock.md— team analytics, stock resources/icons/videos
Official docs
- Introduction & quickstart: https://docs.magnific.com/introduction · https://docs.magnific.com/quickstart
- Authentication: https://docs.magnific.com/authentication
- Webhooks: https://docs.magnific.com/webhooks
- Rate limits / Pricing: https://docs.magnific.com/ratelimits · https://docs.magnific.com/pricing
- MCP: https://docs.magnific.com/modelcontextprotocol
- Full markdown export (for LLMs): https://docs.magnific.com/llms-full.txt
What ships with it: 6 files
153.7 KB alongside SKILL.md
references/
- analytics-and-stock.md32.1 KB
- audio.md18.0 KB
- foundations.md5.4 KB
- image-editing.md17.7 KB
- image-generation.md35.5 KB
- video-generation.md45.0 KB