Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

midjourney-enhanced

server-coding604ISC1.1.6TypeScript support: included

Enhanced fork of the unofficial MidJourney API Node.js client with human verification monitoring, regional painting, and video creation features.

midjourney-api, midjourney-client, midjourney, discord-api, ai-art, image-generation, human-verification, regional-painting, vary-region, video-creation, animate, upscale, variation, fork, enhanced, nodejs, typescript

readme

midjourney-api

Unofficial MidJourney API Node.js client.

English / 中文文档

Notice: This project is an enhanced fork of erictik/midjourney-api. Built upon the original project, we've added human verification monitoring, regional painting, and video creation features. Thanks to the original author for the excellent work!

Discord server npm version

Recent Updates

  • New: Human verification monitoring humanVerify callback function
  • New: Regional painting (first VaryRegion, then WaitVaryRegion after confirmation)
  • New: Video creation (AnimateUpscale/Animate)
  • Face swap
  • Niji bot support
  • Custom zoom
  • Remix mode

Quick Start

This project requires Node.js. Run the following commands in the project root directory:

  1. Download the project code

     git clone https://github.com/erictik/midjourney-api.git
     cd midjourney-api
  2. Install dependencies

     yarn
     # or npm
     npm install
  3. Set environment variables

  4. Get Discord TOKEN Login to Discord Press F12 or [Ctrl + Shift + I] or [Command + Option + I] to open developer tools, then enter the following code in the Console:

    window.webpackChunkdiscord_app.push([
        [Math.random()],
        {},
        (req) => {
            for (const m of Object.keys(req.c)
                .map((x) => req.c[x].exports)
                .filter((x) => x)) {
                if (m.default && m.default.getToken !== undefined) {
                    return copy(m.default.getToken());
                }
                if (m.getToken !== undefined) {
                    return copy(m.getToken());
                }
            }
        },
    ]);
    console.log("%cWorked!", "font-size: 50px");
    console.log(`%cYour token is in the clipboard!`, "font-size: 16px");

    You can also get the discord token by viewing the network Get Discord Token

  5. Join my Discord server

    export SERVER_ID="1262639350852882442"
    export CHANNEL_ID="1262639350852882445"
  6. Or create a Discord server and invite the Midjourney Bot

    # Copy your server URL in the browser
    # `https://discord.com/channels/$SERVER_ID/$CHANNEL_ID`
    export SERVER_ID="your-server-id"
    export CHANNEL_ID="your-channel-id"
  7. Write environment variables to .env file or set them in the console

    #example variables, please set up yours
    
    export SERVER_ID="1262639350852882442"
    export CHANNEL_ID="1262639350852882445"
    export SALAI_TOKEN="your-discord-token"
  8. Now you can run the examples

    npx tsx example/imagine-ws.ts

    or

    yarn example:imagine
    # or npm
    npm run example:imagine
  9. More usage examples

Usage in Your Project

  1. Installation

     npm i midjourney
     # or
     yarn add midjourney
  2. Using Imagine, Variation and Upscale

     import { Midjourney } from "midjourney";
     const client = new Midjourney({
         ServerId: <string>process.env.SERVER_ID,
         ChannelId: <string>process.env.CHANNEL_ID,
         SalaiToken: <string>process.env.SALAI_TOKEN,
         Debug: true,
         Ws: true, //enable ws is required for remix mode (and custom zoom)
     });
     await client.init();
     const prompt = "Christmas dinner with spaghetti with family in a cozy house, we see interior details , simple blue&white illustration";
     //imagine
     const Imagine = await client.Imagine(prompt, (uri: string, progress: string) => {
         console.log("loading", uri, "progress", progress);
     });
     console.log(Imagine);
     if (!Imagine) {
         console.log("no message");
         return;
     }
     // U1 U2 U3 U4 V1 V2 V3 V4  "Vary (Strong)" ...
     const V1CustomID = Imagine.options?.find((o) => o.label === "V1")?.custom;
     if (!V1CustomID) {
         console.log("no V1");
         return;
     }
     // Varition V1
     const Varition = await client.Custom({
         msgId: <string>Imagine.id,
         flags: Imagine.flags,
         customId: V1CustomID,
         content: prompt, //remix mode require content
         loading: (uri: string, progress: string) => {
             console.log("loading", uri, "progress", progress);
         },
     });
     console.log(Varition);
     const U1CustomID = Imagine.options?.find((o) => o.label === "U1")?.custom;
     if (!U1CustomID) {
         console.log("no U1");
         return;
     }
     // Upscale U1
     const Upscale = await client.Custom({
         msgId: <string>Imagine.id,
         flags: Imagine.flags,
         customId: U1CustomID,
         loading: (uri: string, progress: string) => {
             console.log("loading", uri, "progress", progress);
         },
     });
     if (!Upscale) {
         console.log("no Upscale");
         return;
     }
     console.log(Upscale);
     const zoomout = Upscale?.options?.find((o) => o.label === "Custom Zoom");
     if (!zoomout) {
         console.log("no zoomout");
         return;
     }
     // Custom Zoom
     const CustomZoomout = await client.Custom({
         msgId: <string>Upscale.id,
         flags: Upscale.flags,
         content: `${prompt} --zoom 2`, // Custom Zoom  require content
         customId: zoomout.custom,
         loading: (uri: string, progress: string) => {
             console.log("loading", uri, "progress", progress);
         },
     });
     console.log(CustomZoomout);

Human Verification Callback humanVerify (New)

When Discord human verification is triggered (such as requiring CAPTCHA), the SDK will provide the verification page URL through the humanVerify(url) callback. You can display this URL to users for verification completion.

import { Midjourney } from "midjourney";

const client = new Midjourney({
    ServerId: <string>process.env.SERVER_ID,
    ChannelId: <string>process.env.CHANNEL_ID,
    SalaiToken: <string>process.env.SALAI_TOKEN,
    Debug: true,
    Ws: true,
    humanVerify: (url?: string) => {
        // Display the URL to frontend or log it, prompting users to complete verification
        console.log("Human verification required, please visit:", url);
    },
});
await client.init();

Regional Painting (VaryRegion → WaitVaryRegion) (New)

Regional painting workflow:

  • First call VaryRegion to trigger regional repainting, the returned URI is Midjourney's regional painting canvas link;
  • Embed this URI into your webpage (e.g., iframe), users can select regions to repaint on the canvas;
  • After users complete region selection and click submit on the canvas;
  • Call WaitVaryRegion to wait for the regional painting results.

Dependency note: Requires Ws: true to receive real-time events and results.

import { Midjourney } from "midjourney";

const client = new Midjourney({
    ServerId: <string>process.env.SERVER_ID,
    ChannelId: <string>process.env.CHANNEL_ID,
    SalaiToken: <string>process.env.SALAI_TOKEN,
    Debug: true,
    Ws: true,
});
await client.init();

const prompt = "a cozy living room, watercolor, soft light";
const imagine = await client.Imagine(prompt, (uri, progress) => {
    console.log("loading", uri, progress);
});
if (!imagine) throw new Error("imagine failed");

// Step 1: Trigger regional painting, get canvas link
const varyRegionResult = await client.VaryRegion({
    msgId: <string>imagine.id,
    hash: <string>imagine.hash!,
    flags: imagine.flags,
    // Optional: provide prompt here for regional repainting
    content: `${prompt}, add a red pillow on the sofa`,
    loading: (uri, progress) => console.log("varyRegion", uri, progress),
});

if (varyRegionResult?.uri) {
    // Important: Embed this URI into your webpage for user region selection
    console.log("Regional painting canvas link:", varyRegionResult.uri);
    // Example: <iframe src={varyRegionResult.uri} width="100%" height="600px"></iframe>

    // Step 2: After user completes region selection and submits on canvas, wait for results
    const varyResult = await client.WaitVaryRegion({
        msgId: <string>imagine.id,
        // Optional: provide/override prompt again
        content: `${prompt}, add a red pillow on the sofa`,
        loading: (uri, progress) => console.log("waitVaryRegion", uri, progress),
    });
    console.log("Regional painting result:", varyResult);
}

Video Creation (New)

Two methods available:

  • AnimateUpscale: Create video based on single sub-image (U1~U4) (virtual upscale track).
  • Animate: Directly trigger low/high quality video on grid image (low/high).

Dependency note: Recommend enabling Ws: true for progress and results.

import { Midjourney } from "midjourney";

const client = new Midjourney({
    ServerId: <string>process.env.SERVER_ID,
    ChannelId: <string>process.env.CHANNEL_ID,
    SalaiToken: <string>process.env.SALAI_TOKEN,
    Debug: true,
    Ws: true,
});
await client.init();

const prompt = "futuristic city skyline at sunset, ultra detailed";
const imagine = await client.Imagine(prompt);
if (!imagine) throw new Error("imagine failed");

// First upscale a sub-image (e.g., U1), then create video based on upscaled result
const u1 = imagine.options?.find((o) => o.label === "U1")?.custom;
if (!u1) throw new Error("no U1 option");

const upscale = await client.Custom({
    msgId: <string>imagine.id,
    flags: imagine.flags,
    customId: u1,
});
if (!upscale) throw new Error("upscale failed");

// Method 1: Create video based on upscaled image (virtual upscale track)
const video1 = await client.AnimateUpscale({
    index: 1, // Corresponds to U1
    msgId: <string>upscale.id,
    hash: <string>upscale.hash!,
    flags: upscale.flags,
    loading: (uri, progress) => console.log("video_upscale", uri, progress),
});
console.log("video1", video1);

// Method 2: Directly create video on grid image (low/high)
const video2 = await client.Animate({
    msgId: <string>imagine.id,
    hash: <string>imagine.hash!,
    animate_type: "low", // or "high"
    loading: (uri, progress) => console.log("animate", uri, progress),
});
console.log("video2", video2);

Route Map

  • <input checked="" disabled="" type="checkbox"> /imagine variation upscale reroll blend zoomout vary
  • <input checked="" disabled="" type="checkbox"> /info
  • <input checked="" disabled="" type="checkbox"> /fast and /relax
  • <input checked="" disabled="" type="checkbox"> /prefer remix
  • <input checked="" disabled="" type="checkbox"> variation (remix mode)
  • <input checked="" disabled="" type="checkbox"> /describe
  • <input checked="" disabled="" type="checkbox"> /shorten
  • <input checked="" disabled="" type="checkbox"> /settings reset
  • <input checked="" disabled="" type="checkbox"> verify human
  • <input checked="" disabled="" type="checkbox"> varyRegion & waitVaryRegion (regional painting)
  • <input checked="" disabled="" type="checkbox"> animate / video virtual upscale (video creation)
  • <input checked="" disabled="" type="checkbox"> proxy
  • <input checked="" disabled="" type="checkbox"> niji bot
  • <input checked="" disabled="" type="checkbox"> custom zoom
  • <input checked="" disabled="" type="checkbox"> autoload command payload