API Get key

Your first call in four steps.

A plain REST API, JSON in and out. The first two calls cost nothing, so you can prove your key before a credit moves.

  1. 01

    Get a key

    Make a key and keep it on your server. It is shown once.

    Your terminal
    export STAGLIGHT_API_KEY="sl_live_..."
  2. 02

    Check it for free

    These two calls cost nothing: one says who you are and your balance, the other prices a job.

    Is my key good?
    curl -s https://mobyvid.com/api/v1/me \
      -H "Authorization: Bearer $STAGLIGHT_API_KEY"
    What will this job cost?
    curl -s -X POST https://mobyvid.com/api/v1/estimate \
      -H "Authorization: Bearer $STAGLIGHT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"op": "image.nano-banana-pro", "params": {"prompt": "A premium product shot of a glass serum bottle on wet stone, soft window light", "aspect_ratio": "4:5"}}'
  3. 03

    Run a job

    One POST starts Nano Banana Pro. It is charged once, then this code waits for the result and gets the file.

    Open Nano Banana Pro
    # 1. Create the job. It is charged once and refunded if it fails.
    JOB_ID=$(curl -s -X POST https://mobyvid.com/api/v1/jobs \
      -H "Authorization: Bearer $STAGLIGHT_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "op": "image.nano-banana-pro",
        "params": {
          "prompt": "A premium product shot of a glass serum bottle on wet stone, soft window light",
          "aspect_ratio": "4:5"
        },
        "max_credits": 16
      }' | jq -r .id)
    
    # 2. Poll until it finishes. Each call waits up to 30 seconds.
    while :; do
      JOB=$(curl -s "https://mobyvid.com/api/v1/jobs/$JOB_ID?wait=30" -H "Authorization: Bearer $STAGLIGHT_API_KEY")
      case "$(echo "$JOB" | jq -r .status)" in queued|running) ;; *) break ;; esac
    done
    
    # 3. Download the result from outputs[0].download_url.
    DOWNLOAD_URL=$(echo "$JOB" | jq -r '.outputs[0].download_url')
    curl -L -o result.png "$DOWNLOAD_URL"
    import os, uuid, requests
    
    BASE = "https://mobyvid.com/api/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['STAGLIGHT_API_KEY']}"}
    
    # 1. Create the job. It is charged once and refunded if it fails.
    r = requests.post(f"{BASE}/jobs", timeout=60,
                      headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
                      json={
                        "op": "image.nano-banana-pro",
                        "params": {
                          "prompt": "A premium product shot of a glass serum bottle on wet stone, soft window light",
                          "aspect_ratio": "4:5"
                        },
                        "max_credits": 16
                      })
    r.raise_for_status()
    job = r.json()
    
    # 2. Poll until it finishes. Each call waits up to 30 seconds.
    while job["status"] in ("queued", "running"):
        job = requests.get(f"{BASE}/jobs/{job['id']}", headers=HEADERS,
                           params={"wait": 30}, timeout=60).json()
    
    # 3. Download the result from outputs[0].download_url.
    print(job["outputs"][0]["download_url"] if job["outputs"] else job["data"] or job["error"])
    // Node 18 or newer. Save as run.mjs: top-level await needs a module.
    const BASE = "https://mobyvid.com/api/v1";
    const headers = { Authorization: `Bearer ${process.env.STAGLIGHT_API_KEY}` };
    
    // 1. Create the job. It is charged once and refunded if it fails.
    let res = await fetch(`${BASE}/jobs`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
      body: JSON.stringify({
        "op": "image.nano-banana-pro",
        "params": {
          "prompt": "A premium product shot of a glass serum bottle on wet stone, soft window light",
          "aspect_ratio": "4:5"
        },
        "max_credits": 16
      }),
    });
    if (!res.ok) throw new Error((await res.json()).error.message);
    let job = await res.json();
    
    // 2. Poll until it finishes. Each call waits up to 30 seconds.
    while (job.status === "queued" || job.status === "running") {
      job = await (await fetch(`${BASE}/jobs/${job.id}?wait=30`, { headers })).json();
    }
    
    // 3. Download the result from outputs[0].download_url.
    console.log(job.outputs[0]?.download_url ?? job.data ?? job.error);

    POST /api/v1/jobsjob.idGET /api/v1/jobs/{id}?wait=30download_url

  4. 04

    Watch it

    Every job, charge and refund shows in your workspace. A job is always in one of these states.

    Open Task logs

    Job status

    queued
    Accepted and charged. Waiting for its turn.
    running
    The model is working on it.
    succeeded
    Done. The files are in outputs.
    failed
    It did not work. The credits came back on their own.
    canceled
    Canceled before it started. The credits came back.

One prompt. Your agent takes it from here.

Give Claude Code, Codex or Cursor the context to build your Staglight integration. Start with the docs, not a blank page.

Open the documentation index
staglight / agent.prompt
Read the Staglight API documentation:
https://mobyvid.com/llms.txt
https://mobyvid.com/en/docs/api

Build a server-side integration that creates a product image
with POST /api/v1/jobs (op "image.nano-banana-pro"), then polls
GET /api/v1/jobs/{id}?wait=30 until the job has finished.

Read the key from the STAGLIGHT_API_KEY environment variable, never in browser code.
Check the balance first (GET /api/v1/me) and the price (POST /api/v1/estimate).
Send an Idempotency-Key with every paid request. After a timeout, do not retry
blindly: look the job up with GET /api/v1/jobs?idempotency_key=... first.
Return the finished image when its status is succeeded.