1. Get an API key
In the Melius app, go to Team settings → Integrations, create a key, and copy it — it’s shown once. See Authentication for details.2. Make your first request
Paste your key into the snippet below and run it. It creates a project and canvas, adds an image node with your prompt, runs it, waits for the generation to finish, and prints the URL of the generated image.KEY="mel_..."
BASE="https://api.melius.com/api/v1"
AUTH=(-H "Authorization: Bearer $KEY" -H "Content-Type: application/json")
PROJECT=$(curl -s "${AUTH[@]}" -d '{"title":"My first project"}' $BASE/projects | jq -r .id)
CANVAS=$(curl -s "${AUTH[@]}" -d '{"title":"My first canvas"}' $BASE/projects/$PROJECT/canvases | jq -r .id)
NODE=$(uuidgen | tr 'A-Z' 'a-z')
curl -s "${AUTH[@]}" -d "{\"id\":\"$NODE\",\"nodeType\":\"image\",\"geometry\":{\"x\":0,\"y\":0,\"w\":380,\"h\":632},\"textPrompt\":\"a golden retriever puppy in a field\"}" $BASE/canvases/$CANVAS/direct/nodes > /dev/null
RUN=$(curl -s "${AUTH[@]}" -d "{\"canvasId\":\"$CANVAS\"}" $BASE/nodes/$NODE/runs | jq -r .id)
while true; do
STATUS=$(curl -s "${AUTH[@]}" $BASE/node-runs/$RUN | jq -r .status)
[ "$STATUS" = "finished" ] && break
[ "$STATUS" = "failed" ] && { echo "generation failed"; exit 1; }
sleep 2
done
curl -s "${AUTH[@]}" -d '{}' $BASE/node-runs/$RUN/download | jq -r .url
import time, uuid, requests
KEY = "mel_..."
BASE = "https://api.melius.com/api/v1"
auth = {"Authorization": f"Bearer {KEY}"}
project = requests.post(f"{BASE}/projects", headers=auth, json={"title": "My first project"}).json()
canvas = requests.post(f"{BASE}/projects/{project['id']}/canvases", headers=auth, json={"title": "My first canvas"}).json()
node_id = str(uuid.uuid4())
requests.post(f"{BASE}/canvases/{canvas['id']}/direct/nodes", headers=auth, json={
"id": node_id,
"nodeType": "image",
"geometry": {"x": 0, "y": 0, "w": 380, "h": 632},
"textPrompt": "a golden retriever puppy in a field",
})
run = requests.post(f"{BASE}/nodes/{node_id}/runs", headers=auth, json={"canvasId": canvas["id"]}).json()
while True:
status = requests.get(f"{BASE}/node-runs/{run['id']}", headers=auth).json()["status"]
if status in ("finished", "failed"):
break
time.sleep(2)
result = requests.post(f"{BASE}/node-runs/{run['id']}/download", headers=auth, json={}).json()
print(result["url"])
const KEY = "mel_...";
const BASE = "https://api.melius.com/api/v1";
const headers = { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" };
const post = <T>(path: string, body: unknown): Promise<T> =>
fetch(`${BASE}${path}`, { method: "POST", headers, body: JSON.stringify(body) }).then((r) => r.json());
const get = <T>(path: string): Promise<T> => fetch(`${BASE}${path}`, { headers }).then((r) => r.json());
async function main() {
const project = await post<{ id: string }>("/projects", { title: "My first project" });
const canvas = await post<{ id: string }>(`/projects/${project.id}/canvases`, { title: "My first canvas" });
const nodeId = crypto.randomUUID();
await post(`/canvases/${canvas.id}/direct/nodes`, {
id: nodeId,
nodeType: "image",
geometry: { x: 0, y: 0, w: 380, h: 632 },
textPrompt: "a golden retriever puppy in a field",
});
const run = await post<{ id: string }>(`/nodes/${nodeId}/runs`, { canvasId: canvas.id });
let status: string;
do {
await new Promise((r) => setTimeout(r, 2000));
({ status } = await get<{ status: string }>(`/node-runs/${run.id}`));
} while (status !== "finished" && status !== "failed");
const result = await post<{ url: string }>(`/node-runs/${run.id}/download`, {});
console.log(result.url);
}
main();
<?php
$KEY = "mel_...";
$BASE = "https://api.melius.com/api/v1";
function call($method, $path, $body = null) {
global $KEY, $BASE;
$ch = curl_init("$BASE$path");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => $body === null ? null : json_encode($body),
]);
return json_decode(curl_exec($ch), true);
}
function uuidv4() {
$d = random_bytes(16);
$d[6] = chr(ord($d[6]) & 0x0f | 0x40);
$d[8] = chr(ord($d[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($d), 4));
}
$project = call("POST", "/projects", ["title" => "My first project"]);
$canvas = call("POST", "/projects/{$project['id']}/canvases", ["title" => "My first canvas"]);
$nodeId = uuidv4();
call("POST", "/canvases/{$canvas['id']}/direct/nodes", [
"id" => $nodeId,
"nodeType" => "image",
"geometry" => ["x" => 0, "y" => 0, "w" => 380, "h" => 632],
"textPrompt" => "a golden retriever puppy in a field",
]);
$run = call("POST", "/nodes/$nodeId/runs", ["canvasId" => $canvas["id"]]);
do {
sleep(2);
$status = call("GET", "/node-runs/{$run['id']}")["status"];
} while ($status !== "finished" && $status !== "failed");
$result = call("POST", "/node-runs/{$run['id']}/download", new stdClass());
echo $result["url"] . "\n";
package main
import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const key = "mel_..."
const base = "https://api.melius.com/api/v1"
func call(method, path string, body any) map[string]any {
var buf io.Reader
if body != nil {
b, _ := json.Marshal(body)
buf = bytes.NewReader(b)
}
req, _ := http.NewRequest(method, base+path, buf)
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
var out map[string]any
json.Unmarshal(data, &out)
return out
}
func uuidv4() string {
b := make([]byte, 16)
rand.Read(b)
b[6] = (b[6] & 0x0f) | 0x40
b[8] = (b[8] & 0x3f) | 0x80
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16])
}
func main() {
project := call("POST", "/projects", map[string]any{"title": "My first project"})
canvas := call("POST", fmt.Sprintf("/projects/%s/canvases", project["id"]), map[string]any{"title": "My first canvas"})
nodeID := uuidv4()
call("POST", fmt.Sprintf("/canvases/%s/direct/nodes", canvas["id"]), map[string]any{
"id": nodeID,
"nodeType": "image",
"geometry": map[string]any{"x": 0, "y": 0, "w": 380, "h": 632},
"textPrompt": "a golden retriever puppy in a field",
})
run := call("POST", fmt.Sprintf("/nodes/%s/runs", nodeID), map[string]any{"canvasId": canvas["id"]})
status := ""
for status != "finished" && status != "failed" {
time.Sleep(2 * time.Second)
status, _ = call("GET", fmt.Sprintf("/node-runs/%s", run["id"]), nil)["status"].(string)
}
result := call("POST", fmt.Sprintf("/node-runs/%s/download", run["id"]), map[string]any{})
fmt.Println(result["url"])
}
require "net/http"
require "json"
require "securerandom"
KEY = "mel_..."
BASE = "https://api.melius.com/api/v1"
def call(method, path, body = nil)
uri = URI("#{BASE}#{path}")
req = (method == "GET" ? Net::HTTP::Get : Net::HTTP::Post).new(uri)
req["Authorization"] = "Bearer #{KEY}"
req["Content-Type"] = "application/json"
req.body = body.to_json if body
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
JSON.parse(res.body)
end
project = call("POST", "/projects", { title: "My first project" })
canvas = call("POST", "/projects/#{project['id']}/canvases", { title: "My first canvas" })
node_id = SecureRandom.uuid
call("POST", "/canvases/#{canvas['id']}/direct/nodes", {
id: node_id,
nodeType: "image",
geometry: { x: 0, y: 0, w: 380, h: 632 },
textPrompt: "a golden retriever puppy in a field",
})
run = call("POST", "/nodes/#{node_id}/runs", { canvasId: canvas["id"] })
status = nil
until ["finished", "failed"].include?(status)
sleep 2
status = call("GET", "/node-runs/#{run['id']}")["status"]
end
result = call("POST", "/node-runs/#{run['id']}/download", {})
puts result["url"]
modelConfig to the node from List generative models. The x-team-id header is optional — requests default to the team your key belongs to.
Next steps
Authentication
Keys, the
x-team-id header, and how keys are scoped.API overview
The base URL, how generations work, rate limits, and credits.