AI Agent API Reference (OpenAPI)

This document is a minimal, self-contained reference written for AI Agents (Claude Code / OpenClaw / custom agents).

All endpoints return a unified envelope:

{ "code": 0, "message": "success", "data": {}, "requestId": "req_xxx" }

Error handling: treat a response as failed only when code exists and is not 0. If code is null or omitted, do NOT treat it as an error.

Field naming: many endpoints accept both camelCase and snake_case inside data. Parse with fallbacks:

  • Task ID: jobId / job_id / taskId / task_id
  • Upload URL: signedUrl / signed_url
  • Result image URL: imageUrl / image_url; for result lists prefer data.results (each item usually has url), do not rely on result.images only

Authentication

  • Header (either one):
    • Authorization: Bearer <your API key>
    • X-API-Key: <your API key>

Getting an API key: sign in on mopng.cn → open /agent → create an Agent API Key (format ak_...). Keep the key only in your own private configuration; never commit it to a repository.

Choosing an integration path

PathBase URLWhen to use
MoPNG Agent negotiation API (recommended)https://agent-api.mopng.cnLet the server-side agent pick tools, models, and orchestrate the workflow; your agent only states intent, reviews the plan, and collects results
Direct tool API (rest of this page)https://mo-api.mopng.cnYou already know exactly which tool and parameters to call, and want step-by-step control

Both paths share the same API key.

Base paths

  • Direct tool API: /api/v1/open (mo-api.mopng.cn)
  • MoPNG Agent negotiation API: /api/v1/open/agent (agent-api.mopng.cn)

MoPNG Agent negotiation API (recommended)

Best for multi-step image workflows (text-to-image, image-to-image, cutout, background replacement, outpainting, upscaling, and combinations). Flow: submit Brief → server returns Plan → (optional revision rounds) → approve → poll exec for results.

1. List available models (optional)

GET https://agent-api.mopng.cn/api/v1/open/agent/models

Returns the models currently supported for text-to-image generation.

2. Create a session (submit a Brief)

POST https://agent-api.mopng.cn/api/v1/open/agent/session

{
  "version": "1.0",
  "user_intent": "Replace the product background with pure white, keep the shadow natural",
  "spec": {
    "goal": "white-background product photo",
    "subject": {
      "type": "image",
      "reference": "https://example.com/product.png",
      "references": ["https://example.com/product.png"]
    },
    "format": "png"
  },
  "budget": {
    "cost_mode": "balanced",
    "max_cost_points": 10,
    "max_time_sec": 120
  }
}

Field notes:

  • spec.subject.reference must be a publicly reachable HTTPS URL or the literal prompt-only (pure text-to-image). Upload local files to object storage first and pass the URL — never send local paths or base64. Up to 14 reference images via references
  • spec.format: png / jpg / jpeg / webp, default png
  • budget.cost_mode: economy / balanced / premium; when the estimate exceeds max_cost_points the server pauses for your confirmation
  • sensitive (optional): no_face_alter (default false), no_celebrity / no_brand (default true)

The response's session_id is used by every subsequent step.

3. Review the plan

GET /api/v1/open/agent/session/{session_id}/plan

Returns the planned steps, selected models, and cost estimate. Revise if needed.

4. Revise the plan (optional, multiple rounds)

POST /api/v1/open/agent/session/{session_id}/revision

{
  "plan_id": "plan_xxx",
  "round": 2,
  "feedback": [
    { "field": "style", "comment": "Use a light-gray gradient background" }
  ],
  "reason": "Client requested a different background tone"
}

After revising, GET the plan again and review until satisfied.

5. Approve execution

POST /api/v1/open/agent/session/{session_id}/approve

Returns an exec_id.

6. Poll for execution results

GET /api/v1/open/agent/session/{session_id}/exec

  • On success the payload delivers result_image_url (visual-QA plans may return result_text instead of an image)
  • Also reported: steps_log (per-step status), actual models used, actual cost, ai_labeling
  • On failure the status is partial_failed / failed; read error_code and user_message and report honestly — never claim the image was generated

7. Interrupt and clean up (optional)

  • POST /session/{session_id}/interrupt: interrupt a running session
  • DELETE /session/{session_id}: delete a session

Quick example

BASE=https://agent-api.mopng.cn/api/v1/open/agent
KEY="Authorization: Bearer $MOPNG_API_KEY"

# 1. Create a session
SID=$(curl -sS -X POST "$BASE/session" -H "$KEY" -H "Content-Type: application/json" \
  -d '{"version":"1.0","user_intent":"Cut out the subject and export a transparent PNG","spec":{"goal":"cutout transparent png","subject":{"type":"image","reference":"https://example.com/photo.jpg"}}}' \
  | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['session_id'])")

# 2. Review plan → 3. Approve → 4. Poll results
curl -sS "$BASE/session/$SID/plan"  -H "$KEY"
curl -sS -X POST "$BASE/session/$SID/approve" -H "$KEY"
curl -sS "$BASE/session/$SID/exec"  -H "$KEY"

For a full client implementation, use the open-source skill repo: gitee.com/jkin8010/mopng-api (SKILL.md contains the contract and scripts).

Image upload (local files)

When you have a local image file (e.g. ./photo.jpg), upload it first to get a publicly accessible URL, then call the tool endpoints.

POST https://mo-api.mopng.cn/api/v1/images/upload

  • Content-Type: multipart/form-data
  • Body: file field (the image file)
  • Auth: same as above, Authorization: Bearer <your API key>

Response example:

{
  "code": 0,
  "data": {
    "signedUrl": "https://...",
    "signed_url": "https://...",
    "bucket": "...",
    "path": "...",
    "md5": "..."
  }
}

Image input rules

SourceHow to pass it
Local file (e.g. ./a.png)Upload via POST /api/v1/images/upload first, then use the returned signedUrl / signed_url
Remote URL (e.g. https://example.com/photo.jpg)Pass it directly, no upload needed

Async tasks and polling

When a POST response has data.status of pending or processing, poll with the same API key until completed or failed. Do not assume polling is only needed when you set async_mode — the server may always return async tasks.

CapabilityPOST pathPoll with GET (replace {id} with the task ID from the response)
Background removal, upscaling/api/v1/open/image/remove-bg, /api/v1/open/image/upscale/api/v1/open/image/tasks/{id}
Outpainting, translation/api/v1/open/image/outpainting, /api/v1/open/image/translation/api/v1/open/ai/generations/{id} (do not use /image/tasks)
Text-to-image, image-to-image/api/v1/open/ai/generations/api/v1/open/ai/generations/{id}

Task ID: read from data in the first (and polling) responses; accepts jobId / job_id / taskId / task_id.

Result images: prefer data.results (usually an array of objects with url; imageUrl / image_url also possible); if results is absent, fall back to result.imageUrl / result.image_url.

Polling example (background removal / upscaling):

curl -sS "https://mo-api.mopng.cn/api/v1/open/image/tasks/matting-xxxxxxxx-20260320120000" \
  -H "Authorization: Bearer $MOPNG_API_KEY"

For outpainting / translation / text-to-image / image-to-image, poll /api/v1/open/ai/generations/{id} instead.

Polling interval: 2–5 seconds. Apply the same error rule (code exists and is not 0).

Model discovery (text-to-image / image-to-image)

text-to-image and image-to-image are not limited to a single model. Before calling /api/v1/open/ai/generations, query available models:

  • GET https://mo-api.mopng.cn/api/v1/open/ai/models
  • Optional query: type=text_to_image, type=image_edit, etc. (filter by capability)

Recommended agent flow:

  1. Call /api/v1/open/ai/models to list available models.
  2. Filter models supporting the current task (text_to_image or image_to_image).
  3. Use the model field value and check the vendor documentation below for parameter formats.
  4. Validate parameters per the vendor docs (resolution, aspect ratio, image input fields, async behavior).
  5. Then call /api/v1/open/ai/generations.

Note: when vendor docs and actual server behavior disagree, the server response wins.

Vendor model documentation

Bytedance (Volcano Engine Ark)

Aliyun (DashScope)

Copy-paste instructions for agents

Image input: local files must be uploaded first via POST /api/v1/images/upload; use data.signedUrl or data.signed_url. Remote URLs can be passed directly.

If a POST response has data.status pending/processing: poll — cutout/upscale via GET /api/v1/open/image/tasks/{taskId|task_id}; outpainting/translation/text-to-image/image-to-image via GET /api/v1/open/ai/generations/{jobId|task_id}. Same auth as task creation. Result images: prefer data.results[].url.

Before calling /api/v1/open/ai/generations for text-to-image or image-to-image:
1) GET /api/v1/open/ai/models?type=text_to_image (or type=image_edit) to list models;
2) pick a model supporting the target capability (check the type field);
3) confirm parameter formats in the vendor documentation;
4) then build the /api/v1/open/ai/generations request.

Important: the request body uses model (not model_id), and prompt stays at the top level (not nested in parameters).
Text-to-image: type=text_to_image, top-level prompt.
Image-to-image: type=image_to_image, top-level prompt + referenceImages.

Important constraint: image_url / referenceImage

remove-bg, upscale, outpainting, and translation require image_url to be a publicly reachable URL; referenceImage/referenceImages for image-to-image follow the same rule.

  • Local images: upload via POST /api/v1/images/upload first, then use data.signedUrl / data.signed_url
  • Remote URLs: if already a reachable https://... address, pass it directly

remove-bg (background removal)

POST https://mo-api.mopng.cn/api/v1/open/image/remove-bg

Request body example:

{
  "image_url": "https://example.com/input.jpg",
  "output_format": "png",
  "return_mask": false,
  "only_mask": false,
  "async_mode": false
}

Key data fields (camelCase / snake_case compatible):

  • taskId / task_id
  • status: pending|processing|completed|failed
  • When completed: prefer the first item's url in the results array; or result.imageUrl / result.image_url, plus result.maskUrl / result.mask_url (when return_mask=true)

If status is pending / processing, poll GET /api/v1/open/image/tasks/{taskId|task_id} (regardless of async_mode).


upscale (HD upscaling)

POST https://mo-api.mopng.cn/api/v1/open/image/upscale

Request body example:

{
  "image_url": "https://example.com/input.jpg",
  "scale": 2,
  "tile_size": 0,
  "tile_pad": 10,
  "output_format": "png",
  "async_mode": false
}
  • async_mode is optional; even when omitted or false, poll GET /api/v1/open/image/tasks/{taskId|task_id} whenever status is pending / processing.

Response data: taskId/task_id, status, and image URLs in results or result (camelCase / snake_case may both appear).


outpainting (smart expansion)

POST https://mo-api.mopng.cn/api/v1/open/image/outpainting

Request body example:

{
  "provider": "aliyun",
  "model_id": "wanx-outpaint",
  "image_url": "https://example.com/input.jpg",
  "direction": "all",
  "expand_ratio": 0.5,
  "angle": 0,
  "output_ratio": null,
  "best_quality": false
}

Async: if data.status is pending / processing, poll GET /api/v1/open/ai/generations/{jobId|taskId|task_id} (do not use /api/v1/open/image/tasks/...). Prefer data.results[].url when done.


translation (image translation)

POST https://mo-api.mopng.cn/api/v1/open/image/translation

Request body example:

{
  "provider": "aliyun",
  "model_id": "qwen-mt-image",
  "image_url": "https://example.com/text-image.jpg",
  "source_language": "auto",
  "target_language": "en",
  "domain_hint": null,
  "sensitive_word_filter": false,
  "term_intervention": null
}

Async: if data.status is pending / processing, poll GET /api/v1/open/ai/generations/{jobId|taskId|task_id}. Prefer data.results[].url when done. Error rule: code is not None and code != 0.


text-to-image

POST https://mo-api.mopng.cn/api/v1/open/ai/generations

Minimal request (note: use model, not model_id; prompt stays top-level):

{
  "type": "text_to_image",
  "model": "wanx-v2.5",
  "prompt": "A red-billed blue magpie on a branch, blue sky and white clouds behind"
}

Fields:

  • type: text_to_image (required)
  • model: model name (required), e.g. wanx-v2.5, qwen-image-plus, doubao-seedream-4; get the list via GET /api/v1/open/ai/models
  • prompt: prompt text (required), top-level, not nested inside parameters

Task status:

  • GET /api/v1/open/ai/generations/{jobId|job_id|task_id}
  • When completed, prefer data.results (e.g. results[0].url); fall back to the legacy single-object result

image-to-image

POST https://mo-api.mopng.cn/api/v1/open/ai/generations

Upload local images first; remote URLs can be passed as referenceImages. Multiple reference images are supported; for legacy compatibility you may also pass the first image as referenceImage.

Minimal request:

{
  "type": "image_to_image",
  "model": "qwen-image-edit-plus",
  "prompt": "Turn the sky sunset-gold, keep the subject unchanged",
  "referenceImages": [
    "https://example.com/input-a.jpg",
    "https://example.com/input-b.jpg"
  ],
  "referenceImage": "https://example.com/input-a.jpg"
}

Fields:

  • type: image_to_image (required)
  • model: model name (required), e.g. wanx-v2.5, qwen-image-edit-plus
  • prompt: edit instruction (required), top-level
  • referenceImages: array of reference image URLs (recommended, multi-image), top-level
  • referenceImage: single reference URL (compatibility field; when sending multiple, set it to referenceImages[0])

Task status:

  • GET /api/v1/open/ai/generations/{jobId|job_id|task_id}; the result list is data.results