API & MCP server
Generate product photos, infographic cards and videos from your own code — or let an AI assistant do it through the MCP server. Same engine, same prices as the web app.
Quickstart
Create a key in the app under Workspace → API, then queue your first generation. Every request is billed in lyx from the same balance the web app uses.
curl -X POST https://app.photolyx.com/api/v1/generate \
-H "Authorization: Bearer plx_live_…" \
-H "Content-Type: application/json" \
-d '{
"prompt": "White ceramic mug on a marble kitchen counter, morning light, e-commerce product shot",
"model": "gpt-image-2",
"size": "1200x1600"
}'{
"id": "0f2c1a4e-…",
"status": "queued",
"created_at": "2026-08-07T12:00:00.000Z"
}Generation is asynchronous: a photo takes 20–60 seconds, a video up to a few minutes. Poll the job or receive a webhook.
Authentication
Pass the key in the Authorization header. X-Api-Key is accepted as an alternative.
Authorization: Bearer plx_live_…
The key is shown once, at creation. We store only its hash, so a lost key cannot be recovered — issue a new one and revoke the old. Up to 10 active keys per account. A key inherits the account’s balance and, for team members, the owner’s shared pool.
POST /api/v1/generate
Queues a generation and answers 202 with the job.
| Field | Type | Notes |
|---|---|---|
| prompt | string | Required, up to 4000 characters. Any language. |
| model | string | Defaults to gpt-image-2. See GET /api/v1/models. |
| size | string | 1024x1024, 1200x1600 (marketplace card), 1152x2048, 2048x1152 and more. |
| quality | string | low · medium · high. Affects price. |
| count | integer | 1–4 variants in one request (images only). |
| image | string | https URL or data:image/…;base64,…. Turns the call into image-to-image: the product is preserved, the scene is rebuilt. With a video model it becomes the first frame. |
| background | string | transparent for a cut-out PNG (OpenAI models). |
| webhook_url | string | Overrides the key’s default callback for this job. |
GET /api/v1/jobs/:id
curl https://app.photolyx.com/api/v1/jobs/0f2c1a4e-… \ -H "Authorization: Bearer plx_live_…"
{
"id": "0f2c1a4e-…",
"status": "succeeded",
"created_at": "2026-08-07T12:00:00.000Z",
"finished_at": "2026-08-07T12:00:34.000Z",
"result": {
"items": [
{ "id": 91422, "url": "/uploads/gen-….png", "type": "image" }
],
"model": "gpt-image-2",
"credits_spent": 20,
"credits_balance": 980
}
}status is one of queued, running, succeeded, failed. URLs are relative to https://app.photolyx.com and are publicly readable, so you can hand them straight to a marketplace. Failed jobs are never charged: lyx are returned automatically.
GET /api/v1/jobs lists your recent jobs.
Webhooks
Set a default callback per key in the cabinet, or pass webhook_url per request. We POST the same body as GET /api/v1/jobs/:id, wrapped in an event, and retry twice (after 5 and 30 seconds) until you answer 2xx.
POST https://your-service.com/photolyx
x-photolyx-timestamp: 1786000000
x-photolyx-signature: sha256=…
{ "event": "job.succeeded", "data": { … } }Verify the signature — otherwise anyone can forge a callback. It is an HMAC-SHA256 of {timestamp}.{raw body} keyed with the webhook secret shown when the key was created.
import { createHmac, timingSafeEqual } from "crypto";
const expected = "sha256=" + createHmac("sha256", process.env.PHOTOLYX_WEBHOOK_SECRET)
.update(req.headers["x-photolyx-timestamp"] + "." + rawBody)
.digest("hex");
const ok = expected.length === signature.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(signature));Idempotency
Send an Idempotency-Key header with any generation request. A repeat with the same key returns the original job with status 200 instead of creating (and charging) a second one — so a client timeout never costs you twice.
Idempotency-Key: order-4471-main-photo
Balance & models
GET /api/v1/balance → { "balance": 980, "currency": "lyx", … }
GET /api/v1/models → { "data": [ { "id": "gpt-image-2", "kind": "image",
"price_lyx": { "low": 5, "medium": 20, "high": 75 } } ], … }Prices come from the same calculation that charges you, so the catalogue can never drift from the invoice. 1 lyx = $0.01 at list price.
Errors & limits
Every error has the same shape:
{ "error": { "code": "insufficient_credits", "message": "…" } }| unauthorized | 401 — missing, malformed or revoked key. |
| invalid_request | 400 — bad parameters. |
| insufficient_credits | 402 — top up the balance. |
| moderation_blocked | 422 — the provider’s content filter rejected it. Rephrase. |
| rate_limited | 429 — 120 requests per minute per key. |
| too_many_jobs | 429 — at most 8 jobs pending at once. Poll, then submit more. |
| generation_failed | 502 — provider failure. Lyx are refunded. |
MCP server
Photolyx also speaks the Model Context Protocol (stateless HTTP; the revision is negotiated with your client, 2024-11-05 through 2026-07-28). Point any MCP host — Claude Code, Claude Desktop, ChatGPT, Cursor — at the endpoint below and your assistant can shoot product photos and update marketplace cards on its own. The API key is the only credential: nothing to install, no OAuth round-trip.
Claude Code — one command:
claude mcp add --transport http photolyx https://app.photolyx.com/api/mcp \ --header "Authorization: Bearer plx_live_…"
Cursor, Windsurf, ChatGPT developer mode and anything else configured by file:
{
"mcpServers": {
"photolyx": {
"type": "http",
"url": "https://app.photolyx.com/api/mcp",
"headers": { "Authorization": "Bearer plx_live_…" },
"timeout": 600000
}
}
}Keep "type": "http" — an entry that has a url but no type is read as a local stdio server and skipped.timeout (ms) is optional but recommended: hosts cut off a single request after 60 seconds by default, and video jobs run longer than that.
Claude Desktop and claude.ai: Settings → Connectors → Add custom connector, the URL above, then a request header authorization with the value Bearer plx_live_….
Tools exposed:
generate_image— product photos, cards, icons, illustrations; image-to-image editing. Returns the images inline when the job finishes within ~50 seconds, otherwise ajob_idforget_job.build_marketplace_card_prompt— reads the current Wildberries top for a query, including recurring complaints in its reviews, and returns a compliant infographic prompt plus three gallery slides. Free.list_wb_products·set_wb_main_photo— read the seller’s catalogue and replace a card’s main photo.get_job·get_balance.
Wildberries tools require the account to be linked in the app first (Dashboard → Wildberries).