Imgen API v2

Introduction

The Imgen API provides AI-powered image generation with multiple diffusion models, built-in character LoRA support, prompt enhancement, content compliance checking, content credentials, and watermarking. All prompt parsing, workflow construction, and post-processing are handled server-side — clients submit raw prompts and receive signed images hosted on S3.

  • Multiple diffusion models with per-model style presets
  • Optional LLM-powered prompt enhancement
  • Automated content compliance review
  • Configurable output format (JPEG, PNG, WebP, AVIF) with branding watermark
  • C2PA manifest signing, invisible watermark embedding, and PDQ fingerprinting
  • S3-hosted output with pre-signed URLs for the signed image and thumbnail

Base URL

All endpoints accept POST requests with a Content-Type: application/json body containing an action field.

POST https://imgen-stage.api.efficientstack.com/api/v2
Content-Type: application/json
Authorization: Bearer <API-KEY>

{
  "action": "generate",
  ...
}

Authentication

All requests must include a Bearer token in the Authorization header:

Authorization: Bearer <API-KEY>

API keys are managed through the admin panel. Each key tracks request counts and can be enabled or disabled. Requests without a valid, enabled key receive a 401 Unauthorized response.

Prompt Syntax

The API uses a unified raw prompt format. The server parses the following tokens:

TokenSyntaxExampleDescription
Character@name@ayaActivates a character LoRA. One per prompt.
Negative-term-red dressComma-separated term prefixed with - is moved to the negative prompt.
Positiveeverything elseblack lingerie, on bedDescriptive prompt text.

Example

@aya black lingerie, sitting on bed, looking_at_viewer, warm lighting, -red dress, -ugly hands

Parsed as: character=aya, positive=black lingerie, sitting on bed, looking_at_viewer, warm lighting, negative=red dress, ugly hands.

Endpoints

ActionDescription
modelsList available characters, models, and style presets
generateSubmit an image generation job
statusPoll a generation job for completion
optimizeEnhance a prompt with LLM
randomGet a random prompt

POST models

Returns available characters, models, and styles. No parameters beyond action.

{ "action": "models" }

Response

{
  "characters": ["aaliyah", "aya", "bella", "..."],
  "models": {
    "eros": {
      "label": "Eros",
      "default_style": "professional",
      "styles": {
        "professional": { "label": "Professional" },
        "boudoir": { "label": "Boudoir" },
        "..."
      }
    }
  }
}

POST generate

Submit an image generation job. Returns a job ID for polling.

Request Parameters

ParameterTypeRequiredDefaultDescription
actionstringyes"generate"
promptstringyesRaw prompt. Supports @character and -negative.
modelstringno"eros"Diffusion model key.
negativestringno""Additional negatives.
optimizebooleannofalseLLM-enhance the prompt before generation.
widthintegerno1344Image width. Must be a valid pair.
heightintegerno768Image height. Must be a valid pair.
stylestringnomodel defaultStyle preset key for the selected model.
formatstringno"jpeg"jpeg, png, webp, avif.
qualityintegerno95Compression quality (1–100).
losslessbooleannofalseLossless compression (WebP/AVIF).
wm_imagestringno""Watermark as base64 data URI.
wm_positionstringno"bottom-right"Watermark anchor.
wm_scaleintegerno5Watermark scale (1–100).
wm_transparencyintegerno100Watermark opacity (0–100).
wm_rotationintegerno0Rotation degrees (-360–360).
wm_padding_xintegerno10Horizontal padding (0–500).
wm_padding_yintegerno10Vertical padding (0–500).
cs_authorstringno""Override C2PA author.
cs_titlestringno""Override C2PA title.
cs_descriptionstringno""Override C2PA description.
cs_organizationstringno""Override C2PA organization.
cs_vendorstringno""Override C2PA vendor.

Valid Dimensions

1024×1024 (1:1), 1344×768 (16:9), 768×1344 (9:16), 1216×832 (3:2), 832×1216 (2:3), 1152×896 (4:3), 896×1152 (3:4). Invalid pairs fall back to 1344×768.

Response

{
  "id": "run_abc123xyz",
  "prompt": "@aya enhanced prompt text, -red dress",
  "model": "eros",
  "format": "jpeg",
  "gen_id": "a1b2c3d4e5f6g7h8i9j0"
}

POST status

Poll a generation job. Pass the id, prompt, and model returned by generate.

{
  "action": "status",
  "id": "run_abc123xyz",
  "prompt": "@aya enhanced prompt text, -red dress",
  "model": "eros"
}

Pending

{ "status": "IN_QUEUE" }
{ "status": "IN_PROGRESS" }

Completed (Safe)

{
  "status": "COMPLETED",
  "meta": {
    "id": "run_abc123xyz",
    "gen_id": "a1b2c3d4e5f6g7h8i9j0",
    "time": "2025-03-29T20:02:50Z",
    "prompt": "@aya enhanced prompt, -red dress",
    "positive": "photo of aya, enhanced prompt, quality tags",
    "negative": "base negatives, style negatives, red dress",
    "character": "aya",
    "model": "eros",
    "style": "professional",
    "width": 1344,
    "height": 768,
    "format": "jpeg",
    "quality": 95,
    "lossless": false,
    "optimized": true,
    "compliance": "safe",
    "compliance_codes": [],
    "fingerprint": "a4f8e2c1b9d0...",
    "images": [
      { "url": "https://s3...signed.jpg?...", "filename": "genid_fingerprint_00001.jpg", "type": "signed" },
      { "url": "https://s3...thumb.jpg?...", "filename": "genid_fingerprint_00001_thumb.jpg", "type": "thumbnail" }
    ],
    "enable_invisimark": true,
    "enable_c2pa": true,
    "compute_pdq": true,
    "wm_position": "bottom-right",
    "wm_scale": 5,
    "wm_transparency": 100,
    "cs_author": "Author",
    "cs_title": "AI Image",
    "..."
  }
}

Completed (Blocked)

{
  "status": "COMPLETED",
  "compliance": "unsafe",
  "error": "Content blocked — flagged for: Category Name.",
  "filter_categories": ["id1", "id2"]
}

Failed

{ "status": "FAILED", "error": "Generation failed" }

POST optimize

Enhance a prompt independently of generation.

{
  "action": "optimize",
  "prompt": "@aya black lingerie, on bed, -red dress",
  "model": "eros"
}
{
  "prompt": "@aya elegant black lace lingerie, perched on bed, warm lighting, -red dress"
}

POST random

Returns a random prompt. Omit character for random, set empty "" for none, or specify a name.

{ "action": "random" }
{ "action": "random", "character": "aya" }
{ "action": "random", "character": "" }
{ "prompt": "@aya black lace lingerie, sitting on bed, warm lighting" }

Prompt Construction

Positive Prompt

[trigger], [character_positive], {user prompt}[, style quality tags]

Negative Prompt

{base negatives}[, style negatives][, character negatives][, parsed -terms][, explicit negative]

Content Credentials

All generated images include C2PA manifest signing, invisible watermark embedding, and PDQ fingerprinting. The signed image and thumbnail are delivered as pre-signed S3 URLs in meta.images.

Override C2PA metadata per request: cs_author, cs_title, cs_description, cs_organization, cs_vendor.

Polling Strategy

SettingRecommended
Interval3 seconds
Max polls120 (6 min timeout)
Overlap guardWait for each poll to complete before starting the next

Terminal states: COMPLETED, FAILED, TIMED_OUT, CANCELLED. On COMPLETED, always check compliance before accessing meta.

Error Handling

StatusErrorCause
400Missing actionNo action field
400Prompt is requiredEmpty/missing prompt
400Invalid characterUnknown @name
400Bad IDInvalid job ID
401UnauthorizedMissing or invalid API key
502Generation failedUpstream error
502Enhancement failedLLM error

Silent fallbacks: invalid model → first model, invalid dimensions → 1344×768, invalid style → model default, invalid format → jpeg.

Code Examples

const API = 'https://imgen-stage.api.efficientstack.com/api/v2';
const TOKEN = 'your-api-key';

async function api(body) {
  const r = await fetch(API, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TOKEN}` },
    body: JSON.stringify(body)
  });
  return r.json();
}

async function generateImage(prompt, opts = {}) {
  const job = await api({
    action: 'generate', prompt, model: opts.model || 'eros',
    optimize: opts.optimize || false, width: opts.width || 1344,
    height: opts.height || 768, style: opts.style || '', format: opts.format || 'jpeg'
  });
  if (job.error) throw new Error(job.error);

  for (let i = 0; i < 120; i++) {
    await new Promise(r => setTimeout(r, 3000));
    const s = await api({ action: 'status', id: job.id, prompt: job.prompt, model: job.model });
    if (s.status === 'IN_QUEUE' || s.status === 'IN_PROGRESS') continue;
    if (s.status === 'COMPLETED') {
      if (s.compliance === 'unsafe') throw new Error(s.error);
      return s.meta;
    }
    throw new Error(s.error || 'Failed: ' + s.status);
  }
  throw new Error('Timeout');
}

const meta = await generateImage('@aya black lingerie, warm lighting', { style: 'professional' });
const signed = meta.images.find(i => i.type === 'signed');
console.log('Image URL:', signed?.url);
import requests, time

API = "https://imgen-stage.api.efficientstack.com/api/v2"
TOKEN = "your-api-key"

def api(body):
    return requests.post(API, json=body,
        headers={"Authorization": f"Bearer {TOKEN}"}).json()

def generate(prompt, model="eros", style="", fmt="jpeg"):
    job = api({"action":"generate","prompt":prompt,"model":model,"style":style,"format":fmt})
    if "error" in job: raise Exception(job["error"])
    for _ in range(120):
        time.sleep(3)
        s = api({"action":"status","id":job["id"],"prompt":job["prompt"],"model":job["model"]})
        if s["status"] in ("IN_QUEUE","IN_PROGRESS"): continue
        if s["status"] == "COMPLETED":
            if s.get("compliance") == "unsafe": raise Exception(s.get("error"))
            return s["meta"]
        raise Exception(s.get("error", f"Failed: {s['status']}"))
    raise TimeoutError("Polling timed out")

meta = generate("@aya black lingerie, warm lighting", style="professional")
signed = next(i for i in meta["images"] if i["type"] == "signed")
print("URL:", signed["url"])
TOKEN="your-api-key"
BASE="https://imgen-stage.api.efficientstack.com/api/v2"

# List models
curl -s -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"action":"models"}'

# Generate
curl -s -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"action":"generate","prompt":"@aya black lingerie","model":"eros","style":"professional"}'

# Poll status (replace JOB_ID)
curl -s -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"action":"status","id":"JOB_ID","prompt":"@aya ...","model":"eros"}'
<?php
$api = 'https://imgen-stage.api.efficientstack.com/api/v2';
$token = 'your-api-key';

function apiCall($api, $token, $body) {
    $ch = curl_init($api);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($body),
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', "Authorization: Bearer $token"],
    ]);
    $r = curl_exec($ch); curl_close($ch);
    return json_decode($r, true);
}

$job = apiCall($api, $token, ['action'=>'generate','prompt'=>'@aya black lingerie','model'=>'eros']);
for ($i = 0; $i < 120; $i++) {
    sleep(3);
    $s = apiCall($api, $token, ['action'=>'status','id'=>$job['id'],'prompt'=>$job['prompt'],'model'=>$job['model']]);
    if (in_array($s['status'], ['IN_QUEUE','IN_PROGRESS'])) continue;
    if ($s['status'] === 'COMPLETED') {
        if (($s['compliance'] ?? '') === 'unsafe') die($s['error']);
        $signed = array_values(array_filter($s['meta']['images'], fn($i) => $i['type']==='signed'))[0];
        echo "URL: " . $signed['url']; break;
    }
    die($s['error'] ?? 'Failed');
}