Connect to the API
Connect your application: authentication, requests, files and results.
Use Make module operations directly from your server, script, or an n8n HTTP Request node. Make is not required to send HTTP requests.
1. Get a key and check your balance
Register with Apergrex, then create a dedicated integration key in Settings → API. Top up in the cabinet or through the payment API. Generation and processing use your account balance.
Base URL:
https://apergrex.ru/franklab/apiAppend guide paths to this base. For example, /franklab/jobs/image becomes https://apergrex.ru/franklab/api/franklab/jobs/image: the repeated franklab is intentional.
read -rsp 'API key: ' FRANKLAB_KEY; echo
export FRANKLAB_KEY
export FRANKLAB_BASE_URL='https://apergrex.ru/franklab/api'
curl --fail-with-body --max-time 30 \
-H "X-API-Key: ${FRANKLAB_KEY:?Set your API key}" \
"$FRANKLAB_BASE_URL/v1/billing/balance"Keep the key in server-side secrets. Never put it in URLs, browser code, logs, or AI conversations. Each guide specifies the authentication header: utility Make modules use Authorization: Bearer; many generation routes use X-API-Key.
2. Choose an operation and its contract
| Task | Guide | Modules |
|---|---|---|
| Generate or edit video | Video generation | Alibaba Video, HEYGEN AGENT, MARS, MOON, MiniMax, OMNI, SATURN, VECTOR, VENUS, X |
| Generate images, text, speech or music; prepare elements | Images, text and audio | Alibaba Image, JUPITER, KUSOK, MOON GPT, ORKESTR, VOLNA |
| Process files, edit media, add subtitles or audit SEO | Utilities and montage | C2PA, FORSAJ, HOLST, INDEXLIFT, KLEY, OVERLAY, PLASTINKA, SPEKTR, SUFLER |
A Make label helps you find an operation, but is not necessarily a REST parameter. Use the values in the operation example, not dropdown labels or {{parameters.…}} expressions. One module may call multiple routes with different response shapes.
3. Prepare input files
Direct links or uploaded files
If an operation accepts imageUrl, videoUrl or another URL field, you can use a direct public HTTPS link without uploading first. A cloud-storage link must return the actual file without login, cookies or an authorization header. A sharing page, HTML preview, local path or browser blob: URL is not a media file link. Keep the link accessible for the whole processing period; an expired link must be replaced before a new request. The import endpoint below rejects private/local addresses and unsafe redirects.
For a local file, use multipart upload. Replace input.png with your file:
set -e
curl --fail-with-body --max-time 120 \
-H "Authorization: Bearer ${FRANKLAB_KEY:?Set your API key}" \
-F 'file=@./input.png;type=image/png' \
"$FRANKLAB_BASE_URL/franklab/jobs/upload" \
-o upload.json
jq -e '.success == true and (.data.storedFileId | type == "string")' upload.json >/dev/null
jq '.data | {url,storedFileId,mimeType,sizeBytes,expiresAt}' upload.jsonDo not set Content-Type: application/json for multipart: cURL supplies the boundary. Upload returns {success:true,data:{url,storedFileId,mimeType,sizeBytes,expiresAt}}. The existing data.url goes into URL fields; data.storedFileId is the file ID belonging to your account. Uploaded source files are retained for 7 days. Upload accepts supported image/video/audio files up to 150 MiB and does not convert their format; each processing operation can impose stricter limits.
Import a URL or inspect an uploaded file
Some inputs, such as Alibaba firstFrame, need a descriptor with a file ID and measured dimensions. Use POST /franklab/jobs/import, authenticated with the same account key. Send kind and exactly one of url or storedFileId:
kind | Import formats | Maximum file size |
|---|---|---|
image | PNG, JPEG, WebP | 30 MiB |
video | MP4, MOV, WebM | 100 MiB |
audio | Supported audio formats; keep within the target operation's format limits | 50 MiB |
document | PDF, TXT, MD | 20 MiB |
Export Word, Excel, PowerPoint and other office documents as PDF before importing them. Import inspects the actual bytes; it does not transcode a file or make it compatible with every model.
Import an image from a direct link:
set -e
jq -n --arg url 'https://media.example.com/product-front.png' \
'{url:$url,kind:"image"}' > import-request.json
curl --fail-with-body --max-time 180 \
-H "Authorization: Bearer ${FRANKLAB_KEY:?Set your API key}" \
-H 'Content-Type: application/json' \
--data-binary @import-request.json \
"$FRANKLAB_BASE_URL/franklab/jobs/import" \
-o imported.json
jq -e '.success == true and (.data.storedFileId | type == "string")' imported.json >/dev/null
jq '.data' imported.jsonFor an image you already uploaded, use the saved response to import by ID instead:
set -e
jq -e '.data | {storedFileId,kind:"image"} | select(.storedFileId | type == "string" and length > 0)' \
upload.json > import-request.json
curl --fail-with-body --max-time 180 \
-H "Authorization: Bearer ${FRANKLAB_KEY:?Set your API key}" \
-H 'Content-Type: application/json' \
--data-binary @import-request.json \
"$FRANKLAB_BASE_URL/franklab/jobs/import" \
-o imported.json
jq -e '.success == true and (.data.storedFileId | type == "string")' imported.json >/dev/null
jq '.data' imported.jsonThe response is {success:true,data:{storedFileId,url,mimeType,sizeBytes,width?,height?,durationSeconds?,fps?,pageCount?}}. Optional fields appear when applicable to the inspected file: image dimensions, video dimensions/duration/frame rate, audio duration or PDF page count. Use the measured fields returned by the API, rather than guessed values. A newly imported source is retained for 14 days; inspecting an existing uploaded file does not extend its original expiry. See the Alibaba first-frame example for building a descriptor from this response.
Qwen image editing
For POST /make/alibaba/images, the simplest input is editImageUrls: 1–3 direct HTTPS URLs, PNG/JPEG/WebP, 10 MiB maximum per image. Qwen's limit is lower than the generic image-import limit. The server imports these references for your account:
{
"model": "qwen-image-3.0",
"operation": "image_edit",
"prompt": "Replace the background with a pale blue studio backdrop.",
"width": 1024,
"height": 1024,
"editImageUrls": ["https://media.example.com/product-front.png"]
}Alternatively, collect uploaded data.storedFileId values into editImageIds. For the single image in upload.json:
jq -e '.data.storedFileId | select(type == "string" and length > 0) | {model:"qwen-image-3.0",operation:"image_edit",prompt:"Replace the background with a pale blue studio backdrop.",width:1024,height:1024,editImageIds:[.]}' \
upload.json > qwen-request.jsonSend exactly one of editImageUrls or editImageIds. Neither field is a MOON GPT file ID or a Make {value} object. Before submitting the generation, estimate it with the selected model, qwenOperation:"image_edit", imageCount, width, height and n; estimates do not download the references. See Qwen operations for the full request and result contract.
Other modules can use direct URLs, their own upload API or different IDs. Follow the input shape in the module guide; file IDs from separate systems are not interchangeable.
4. Estimate the cost and create one task
Use the estimate for the exact route, model and parameters. Compare it with available; the price list contains base rates, not a guaranteed personal quote. The operation guide notes when a separate estimator is absent; an unknown cost does not mean zero.
The complete MARS example covers balance → estimate → submit → status → video URL. Submission may reserve funds. Do not run every catalog example in sequence.
5. Retrieve the result
Save the returned ID immediately. Poll the matching operation's status route using the same account. Response formats differ:
| Family | Identifier and result |
|---|---|
| MARS text2video | data.task_id, data.task_status; successful output at data.task_result.videos[0].url |
| Make jobs facade | data.taskId, data.status; output at data.result.downloadUrl |
| Other operations | Follow the module contract: synchronous response, separate task, or another output shape |
Bound your poll count and wait time. Keep the ID when the wait expires and check it later. On a submission timeout, 5xx, or missing ID, do not automatically repeat POST: the server may have accepted the task. Check history and contact support. The payment API's Idempotency-Key does not make arbitrary generation routes idempotent.
Verify that the result is accessible. Download and decode media; inspect text responses. Reconcile the final charge against transactions. Estimate, reservation and final cost can differ.
Python: verify your connection
Uses the standard library with no extra packages. This example only reads the balance.
import json
import os
from urllib.request import Request, urlopen
base = "https://apergrex.ru/franklab/api"
request = Request(base + "/v1/billing/balance", headers={
"X-API-Key": os.environ["FRANKLAB_KEY"],
})
with urlopen(request, timeout=30) as response:
balance = json.load(response)
print({name: balance.get(name) for name in ("available", "reserved")})For a generation JSON request, set method="POST", data=json.dumps(payload).encode() and Content-Type: application/json. Take the payload, submit path and status path from the module guide. Do not add automatic task-creation retries.
JavaScript: verify your connection
For server-side Node.js with built-in fetch. This example only reads the balance.
const key = process.env.FRANKLAB_KEY;
if (!key) throw new Error("Set FRANKLAB_KEY");
const base = "https://apergrex.ru/franklab/api";
const response = await fetch(`${base}/v1/billing/balance`, {
headers: { "X-API-Key": key },
redirect: "error",
signal: AbortSignal.timeout(30000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { available, reserved } = await response.json();
console.log({ available, reserved });For a generation JSON request, add method: "POST", body: JSON.stringify(payload) and Content-Type: application/json. Before continuing, check both HTTP status and the contract's success/error fields.
Share documentation with AI
Each section supports opening, downloading and copying Markdown, and handing it to AI. Share the relevant family guide together with this connection guide. Insert the real API key only in your own environment after reviewing the generated code.