Skip to main content

🎯 Understand the Core Concept

The MidJourney API simulates Discord button interactions. Unlike typical REST APIs, it works as a state machine where each operation returns new buttons for the next step.

The 4 Core APIs

APIPurposeWhen to Use
POST /mj/submit/imagineText-to-image generationStarting point for all workflows
GET /mj/task/\{id\}/fetchQuery task status & get buttonsAfter every submit (poll until done)
POST /mj/submit/actionClick a button (upscale, vary, zoom, etc.)When you want to operate on an image
POST /mj/submit/modalSubmit additional inputOnly when status is MODAL

📊 Complete Workflow Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                         MIDJOURNEY API WORKFLOW                             │
└─────────────────────────────────────────────────────────────────────────────┘

  ┌──────────────────┐
  │  POST /submit/   │  ← Step 1: Submit prompt, get task_id
  │     imagine      │
  └────────┬─────────┘
           │ Returns: { "result": "task_id_1" }

  ┌──────────────────┐
  │ GET /task/{id}/  │  ← Step 2: Poll until status = "SUCCESS"
  │      fetch       │
  └────────┬─────────┘
           │ Returns: imageUrl + buttons[] (U1,U2,U3,U4,V1,V2,V3,V4,🔄)

  ┌──────────────────┐
  │  POST /submit/   │  ← Step 3: Click a button using customId
  │     action       │
  └────────┬─────────┘
           │ Returns: { "result": "task_id_2" }

  ┌──────────────────┐
  │ GET /task/{id}/  │  ← Step 4: Poll the new task
  │      fetch       │
  └────────┬─────────┘

           ├─── status = "SUCCESS" → Done! Get imageUrl

           └─── status = "MODAL" → Need additional input (see Step 5)


           ┌──────────────────┐
           │  POST /submit/   │  ← Step 5: Submit mask/prompt for special operations
           │      modal       │
           └────────┬─────────┘
                    │ Returns: { "result": "task_id_3" }

           ┌──────────────────┐
           │ GET /task/{id}/  │  ← Step 6: Poll until SUCCESS
           │      fetch       │
           └──────────────────┘

🔑 Key Concept: Buttons & customId

Every successful task returns a buttons array. Each button has a customId that you use to trigger the next action. Example response from /mj/task/\{id\}/fetch:
{
  "status": "SUCCESS",
  "imageUrl": "https://api.cometapi.com/mj/image/xxx",
  "buttons": [
    { "customId": "MJ::JOB::upsample::1::abc123", "label": "U1" },
    { "customId": "MJ::JOB::upsample::2::abc123", "label": "U2" },
    { "customId": "MJ::JOB::variation::1::abc123", "label": "V1" },
    { "customId": "MJ::JOB::reroll::0::abc123", "emoji": "🔄" }
  ]
}
⚠️ Important: customId is NOT a fixed value. It changes for every task. Always get it from the buttons array.

📋 Button Reference by Stage

After IMAGINE (4-grid image)

These buttons are returned when your initial image generation completes:
ButtoncustomId PatternActionResult
U1-U4MJ::JOB::upsample::1::xxxUpscale single imageHigh-res single image
V1-V4MJ::JOB::variation::1::xxxGenerate variationsNew 4-grid
🔄MJ::JOB::reroll::0::xxx::SOLORegenerate allNew 4-grid

After UPSCALE (single image)

After upscaling, you get access to editing tools:
LabelNeeds Modal?
Upscale (Subtle) / Upscale (2x)❌ No
Upscale (Creative) / Upscale (4x)❌ No
Vary (Subtle) 🪄❌ No
Vary (Strong) 🪄❌ No
Vary (Region) 🖌️✅ Yes (mask)
Zoom Out 2x / 1.5x 🔍❌ No
Custom Zoom 🔍✅ Yes (prompt)
⬅️➡️⬆️⬇️ Pan❌ No
Animate 🎞️❌ No
🔄 Reroll❌ No
Note: Button labels and customId formats may vary depending on the MJ version specified in your prompt (e.g., --v 6.1 vs --v 5.2). Always read buttons from the API response.
⚠️ Inpaint (Vary Region) button only appears after Upscale!

⚡ Complete Example: Generate & Upscale

Step 1: Submit Imagine Request

curl -X POST 'https://api.cometapi.com/mj/submit/imagine' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "botType": "MID_JOURNEY",
    "prompt": "a cute cat --v 6.1",
    "accountFilter": { "modes": ["FAST"] }
  }'
Response:
{ "code": 1, "result": "1768464763141701" }

Step 2: Poll Task Status

curl -X GET 'https://api.cometapi.com/mj/task/1768464763141701/fetch' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>'
Response (when complete):
{
  "status": "SUCCESS",
  "imageUrl": "https://api.cometapi.com/mj/image/1768464763141701",
  "buttons": [
    { "customId": "MJ::JOB::upsample::1::5f20922e-xxx", "label": "U1" },
    { "customId": "MJ::JOB::upsample::2::5f20922e-xxx", "label": "U2" },
    ...
  ]
}

Step 3: Click U1 to Upscale

curl -X POST 'https://api.cometapi.com/mj/submit/action' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "taskId": "1768464763141701",
    "customId": "MJ::JOB::upsample::1::5f20922e-xxx"
  }'
Response:
{ "code": 1, "result": "1768464800000000" }

Step 4: Poll New Task & Get Result

curl -X GET 'https://api.cometapi.com/mj/task/1768464800000000/fetch' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>'

⚠️ When is Modal Required?

When you call /mj/submit/action and the task status becomes MODAL instead of SUCCESS, you must call /mj/submit/modal to provide additional input.

Confirmed Modal Operations

OperationButtonWhat to Submit
InpaintVary (Region)maskBase64 (PNG mask) + prompt
Custom Zoom🔍 Custom Zoomprompt (e.g., “your prompt —zoom 2”)
Example: Inpaint Flow
# 1. Click Vary (Region) button via Action API
curl -X POST 'https://api.cometapi.com/mj/submit/action' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{"taskId": "xxx", "customId": "MJ::Inpaint::xxx", "enableRemix": true}'

# 2. Poll and see status = "MODAL"
curl -X GET 'https://api.cometapi.com/mj/task/new_task_id/fetch'
# Response: { "status": "MODAL" }

# 3. Submit mask and prompt via Modal API
curl -X POST 'https://api.cometapi.com/mj/submit/modal' \
  -H 'Authorization: Bearer <YOUR_COMETAPI_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "taskId": "new_task_id",
    "prompt": "replace with golden crown",
    "maskBase64": "data:image/png;base64,..."
  }'

🚀 Speed Mode Selection

Add speed prefix to the path:
ModePath PrefixExample
Fast/mj-fast/mj-fast/mj/submit/imagine
Turbo/mj-turbo/mj-turbo/mj/submit/imagine
Relax(default)/mj/submit/imagine

🔗 Other Entry Points

These APIs are independent entry points that don’t follow the imagine → action flow:
APIPurpose
POST /mj/submit/blendBlend 2-5 images into one
POST /mj/submit/describeGenerate prompt from image
POST /mj/submit/videoConvert image to video
POST /mj/submit/editsEdit image with mask

❓ Troubleshooting Tips

Based on the API design and workflow, here are common issues you may encounter:
ProblemLikely CauseSolution
Can’t find Vary (Region) buttonLooking at 4-grid imageUpscale first (click U1-U4), then check buttons
Task status stuck at MODALOperation requires additional inputCall /mj/submit/modal with required data
customId not workingUsing outdated or hardcoded valueAlways get fresh customId from /mj/task/\{id\}/fetch response
Empty buttons arrayTask still in progressWait for status: "SUCCESS" before accessing buttons