API v1/Durable image infrastructure

Build creative workflows that survive the request.

Queue Ultra Max artwork, preserve reference intent, vectorize outputs, and recover every private asset through one project-scoped API.

Start

Five-minute quickstart

Create a development project and scoped key in the console, then send one durable request from your server. Secret keys must never ship in browser or mobile code.
  1. 01

    Create a project

    Use a development project to isolate keys, jobs, assets, and limits.

  2. 02

    Issue a scoped key

    Select generations:create, generations:read, and assets:read. Copy the secret once.

  3. 03

    Queue the job

    Send an Idempotency-Key. A 202 response means the durable record exists.

  4. 04

    Poll and download

    Respect Retry-After, wait for completed, then follow the authenticated file redirect.

curl · queue generation
export DESIGNGEN_API_KEY="dgv1_…"
export DESIGNGEN_PROJECT_ID="project_…"

curl https://platform.trydesigngen.com/v1/generations \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "'"$DESIGNGEN_PROJECT_ID"'",
    "operation": "generate",
    "quality": "ultra-max",
    "prompt": {
      "text": "A one-color vintage racing emblem for a black shirt",
      "mode": "enhance",
      "lockedText": ["NIGHT SHIFT"]
    },
    "output": {
      "resolution": "2K",
      "aspectRatio": "1:1",
      "format": "png",
      "count": 1,
      "background": "transparent"
    }
  }'
curl · poll and download
curl "https://platform.trydesigngen.com/v1/generations/$GENERATION_ID?projectId=$DESIGNGEN_PROJECT_ID" \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY"

# Respect Retry-After on the create response. When status is completed:
curl -L "https://platform.trydesigngen.com/v1/generations/$GENERATION_ID/files/png?projectId=$DESIGNGEN_PROJECT_ID" \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  --output design.png

Foundation

Authentication and projects

Every API key belongs to one project and environment. Send it as a bearer token; the server enforces its scopes, project binding, account eligibility, and status.

Key rules

  • Keys begin with dgv1_ and the secret is shown only at creation.
  • Use separate development and production projects. Never reuse a customer-facing key.
  • Rotate by creating a replacement, switching traffic, then revoking the old key.
  • A project ID is optional only when the credential resolves one unambiguous project.

Use the smallest scope set

Creation, read, prompt, vector, asset deletion, and webhook management are independent permissions. A key can be revoked without deleting its durable jobs.
POST/v1/developer/projects

Create a project from an authenticated console session.

POST/v1/developer/api-keys

Create a project-bound key; the secret is returned once.

DELETE/v1/developer/api-keys/{keyId}

Revoke a key without removing its historical usage.

Inputs

Private assets

Store source and reference images before generation. Direct uploads send the file to project-scoped private storage without passing its bytes through the web API.

Signed uploads accept PNG, JPEG, WebP, and safe SVG files up to 20 MB. The completion call verifies the actual bytes, type, size, and optional SHA-256 before the asset becomes usable. SVGs must omit DOCTYPE declarations and active or externally loaded content.

Use purpose: source for a screenshot or primary reconstruction input; use reference for supporting material.

Downloads use /v1/assets/{assetId}/content, require assets:read, and respond with a short-lived redirect. Do not persist the redirected URL.

curl · direct private upload
FILE="reference.png"
CONTENT_TYPE="image/png"
FILE_SIZE="$(wc -c < "$FILE" | tr -d ' ')"
SHA256="$(shasum -a 256 "$FILE" | awk '{print $1}')"

INTENT="$(curl -sS https://platform.trydesigngen.com/v1/assets/uploads \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "'"$DESIGNGEN_PROJECT_ID"'",
    "fileName": "'"$FILE"'",
    "contentType": "'"$CONTENT_TYPE"'",
    "sizeBytes": '"$FILE_SIZE"',
    "purpose": "reference",
    "sha256": "'"$SHA256"'"
  }')"

ASSET_ID="$(printf '%s' "$INTENT" | jq -r '.data.id')"
UPLOAD_URL="$(printf '%s' "$INTENT" | jq -r '.upload.url')"
curl --fail -X PUT "$UPLOAD_URL" \
  -H "Content-Type: $CONTENT_TYPE" \
  -H "x-goog-content-length-range: $FILE_SIZE,$FILE_SIZE" \
  -H "x-goog-if-generation-match: 0" \
  --upload-file "$FILE"

curl -sS "https://platform.trydesigngen.com/v1/assets/$ASSET_ID/complete" \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"'"$DESIGNGEN_PROJECT_ID"'","sha256":"'"$SHA256"'"}'

Treat the returned upload URL like a short-lived secret. Use it once, with the exact returned method and headers, then call completion. Remote URL import is intentionally unavailable during the polling-first launch.

Control

Prompt Writer

Preview the exact effective prompt before spending generation credits. The response keeps original and enhanced text, locked copy, reference instructions, warnings, and writer version.
preserve

Use your prompt without creative rewriting.

auto

Apply restrained improvements when they clarify the request.

enhance

Actively structure composition, production intent, and reference roles.

Locked text is an instruction, not OCR

Use lockedText for exact copy that must be preserved. Always inspect final artwork before production.
curl · preview effective prompt
curl https://platform.trydesigngen.com/v1/prompts/enhance \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "project_…",
    "operation": "generate_with_reference",
    "text": "Make a clean launch graphic",
    "mode": "enhance",
    "lockedText": ["ORBIT CLUB"],
    "references": [
      { "assetId": "asset_…", "role": "style" },
      { "assetId": "asset_…", "role": "logo" }
    ],
    "output": { "resolution": "2K", "aspectRatio": "1:1" }
  }'

Inspect

Artwork analysis separates facts from assessment

Send an HTTPS artwork URL to receive typed image facts, optional print measurements, provenance, and visual suggestions for naming, search, palette, and mockups. This beta contract is useful for a review queue; it is not a rights, spelling, compliance, or print-quality decision.

Use a server-side key with design_analysis scope. The route accepts an HTTPS image URL, optional prompt context, astandard profile, caller metadata, and optional print-target controls for rules-based measurements.

Separate facts from inferences

facts and print measurements are decoded or rules-based observations. assessment contains visual suggestions such as titles, tags, detected text, audiences, mockup pairings, and risk counts. Keep a human decision in your workflow.

The response includes profile and provenance in the beta contract. Verify account access before routing customer artwork.

typescript · server-side analysis
// Run this only in your server environment. The browser calls your backend.
const response = await fetch('https://platform.trydesigngen.com/v1/design-analysis', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DESIGNGEN_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    imageUrl: 'https://assets.example.test/artwork.png',
    designPrompt: 'One-color shop shirt artwork',
    profile: 'standard',
    printTarget: { width: 12, height: 16, unit: 'in', method: 'dtf' },
    metadata: { externalArtworkId: 'ams-art-42' },
  }),
});

if (!response.ok) throw new Error(`Analysis failed: ${response.status}`);
const { data } = await response.json();
// facts and printAssessment are typed observations; assessment is a suggestion layer.
// The analysis field remains available only as the original flat compatibility projection.
return data;

Create

Three Ultra Max generation modes

All modes create the same durable resource. Only their reference contract changes. Output count is currently one; supported formats are PNG and WebP at 1K, 2K, or 4K.
generate

Prompt to design

Do not include references. Choose preserve, auto, or enhance and describe standalone artwork—not a shirt mockup.

json · generate
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "'"$DESIGNGEN_PROJECT_ID"'",
    "operation": "generate",
    "quality": "ultra-max",
    "prompt": {
      "text": "A one-color vintage racing emblem for a black shirt",
      "mode": "enhance",
      "lockedText": ["NIGHT SHIFT"]
    },
    "output": {
      "resolution": "2K",
      "aspectRatio": "1:1",
      "format": "png",
      "count": 1,
      "background": "transparent"
    }
  }'
generate_with_reference

Role-aware references

Provide 1–14 unique assets. Assign each one a role: product, logo, style, layout, background, or source.

json · generate with reference
{
  "projectId": "project_…",
  "operation": "generate_with_reference",
  "quality": "ultra-max",
  "prompt": { "text": "A premium club graphic", "mode": "enhance" },
  "references": [
    { "assetId": "asset_style…", "role": "style" },
    { "assetId": "asset_logo…", "role": "logo" }
  ],
  "output": {
    "resolution": "2K", "aspectRatio": "1:1", "format": "png",
    "count": 1, "background": "transparent"
  }
}
screenshot_to_design

Screenshot to artwork

Provide exactly one reference with the source role. Supporting references may use the remaining roles.

json · screenshot to design
{
  "projectId": "project_…",
  "operation": "screenshot_to_design",
  "quality": "ultra-max",
  "prompt": { "text": "Rebuild this as standalone apparel artwork", "mode": "enhance" },
  "references": [{ "assetId": "asset_screenshot…", "role": "source" }],
  "output": {
    "resolution": "2K", "aspectRatio": "1:1", "format": "png",
    "count": 1, "background": "transparent"
  }
}

Beta

Vectorization through the new pipeline

Queue an existing project asset for print, detail, or simple tracing and request any supported combination of SVG, PDF, PNG, EPS, and DXF.

Vectorization is a named beta

Quality and billing policy may change before general availability. Treat the job response and usage ledger as the authority for credits actually applied.

Poll GET /v1/vectorizations/{id}. After completion, download a requested format from /files/{format}.

curl · queue vectorization
curl https://platform.trydesigngen.com/v1/vectorizations \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "project_…",
    "sourceAssetId": "asset_…",
    "profile": "print",
    "formats": ["svg", "pdf", "png"]
  }'

Invite-only beta

Operator production workflows

Start print_file_fix, legacy dtf_file_fix, or screenshot_to_design with account-owned artwork. Read lifecycle, artifacts, events, and review gates before a final download or approval.

Enroll before integrating

Operator beta requires an invited account with Pro or Enterprise developer access and Operator access. API keys need operator_write to upload, start runs and answer decisions, operator_read to retrieve progress and results, and usage_read to reconcile credits. Operator uses account-owned uploads, not project asset IDs or projectId.

Print-file workflows use Light US and need targetWidthIn, up to 24 inches. Use approvalMode: preview to review an exact artifact version before final vectorization, 600-DPI preparation, final QA, and export. maxCredits can lower, but never raise, the account's run limit. Screenshot-to-design rejects a print width and preview approval mode. For large files, use the upload endpoint's sign and complete actions documented in OpenAPI instead of multipart upload. The maximum file size is 25 MB.

Read GET run state for lifecycle: working, preview_ready, awaiting_input, awaiting_approval, finalizing, final_ready, failed, or canceled. The response has an ETag: send it as If-Match for attachment, cancel, resume, or retry writes. Use decisions only for runtime-supplied approval IDs, including their exact artifact/version binding. Send allow_once only after reviewing that version; corrections require a fresh preview and stale approvals return 409.

GET /v1/developer/usage reports an account-wide Operator ledger. Only settledCredits is actual spend. reservedCredits is in-flight exposure and releasedCredits is refunded work; the apiKeyId filter applies only to normal request history.

Completed does not mean print-ready

The production package returns 202 while work is active. A terminal response returns 200 even when ready is false. Review warnings and checks; use files only when ready is true and their visual fidelity is acceptable. Download URLs expire; refetch the package or use the owned artifact download route to refresh them. Reconnect SSE using Last-Event-ID or after, then use cursor polling to reconstruct history. Generation webhooks below do not report Operator runs.
curl · upload, repair and inspect
# Enroll in the Operator beta and create a key with
# operator_write, operator_read, and usage_read scopes.
UPLOAD=$(curl -sS https://platform.trydesigngen.com/v1/operator/uploads \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -F "file=@artwork.png")
ARTIFACT_ID=$(printf '%s' "$UPLOAD" | jq -r '.artifact_id')

# Save this key and reuse it only when retrying this exact request.
REQUEST_KEY=$(uuidgen)
RUN=$(curl -sS https://platform.trydesigngen.com/v1/operator/runs \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Idempotency-Key: $REQUEST_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"workflow\":\"print_file_fix\",\"attachmentRef\":\"$ARTIFACT_ID\",\"targetWidthIn\":12,\"approvalMode\":\"preview\",\"maxCredits\":500,\"modelTier\":\"light_us\"}")
RUN_ID=$(printf '%s' "$RUN" | jq -r '.run.id')

curl -sS "https://platform.trydesigngen.com/v1/operator/runs/$RUN_ID/production-package" \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY"

Delivery

Polling is the launch path.

A create response returns HTTP 202, a canonical resource, a Location header, and a Retry-After hint. The resource is the source of truth even when a delivery is delayed or duplicated.
queued

Accepted and waiting for a worker.

running

In progress; inspect stage for orientation.

awaiting_input

A current question needs a scoped answer or attachment.

awaiting_approval

A runtime-supplied decision needs an explicit choice.

completed

Output asset IDs and authenticated file routes are available.

blocked

Stopped by a safety or policy decision.

failed

Inspect error and retryable before deciding to resubmit.

cancelled

Cancelled before delivery; no output should be expected.

Signed delivery

Webhook creation and delivery are explicitly gated off for the initial launch. Requests return 403 until network-level egress enforcement and destination controls are operational. Integrations should poll the canonical resource URL.

After webhook activation, DesignGen signs timestamp.rawBody with HMAC-SHA256. Verify raw bytes before parsing, reject stale timestamps, and deduplicate on X-DesignGen-Delivery.

curl · available after webhook activation
curl https://platform.trydesigngen.com/v1/developer/webhooks \
  -H "Authorization: Bearer $DESIGNGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "project_…",
    "url": "https://api.example.com/webhooks/designgen",
    "events": ["generation.completed", "generation.failed"]
  }'
node · verify signature
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyDesignGen(rawBody, header, secret) {
  const fields = Object.fromEntries(header.split(',').map(v => v.split('=')));
  if (!fields.t || !fields.v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(fields.t)) > 300) return false;
  const expected = createHmac('sha256', secret)
    .update(`${fields.t}.${rawBody}`)
    .digest('hex');
  const given = Buffer.from(fields.v1, 'hex');
  const wanted = Buffer.from(expected, 'hex');
  return given.length === wanted.length && timingSafeEqual(given, wanted);
}
python · verify signature
import hashlib, hmac, time

def verify_designgen(raw_body: bytes, header: str, secret: str) -> bool:
    fields = dict(part.split("=", 1) for part in header.split(","))
    if abs(time.time() - int(fields["t"])) > 300:
        return False
    signed = fields["t"].encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, fields["v1"])
curl / openssl · verify
# Use the raw request bytes saved as payload.json.
timestamp="$(printf '%s' "$DESIGNGEN_SIGNATURE" | sed -E 's/^t=([0-9]+),.*/\1/')"
received="$(printf '%s' "$DESIGNGEN_SIGNATURE" | sed -E 's/.*v1=([0-9a-f]+)$/\1/')"
expected="$( { printf '%s.' "$timestamp"; cat payload.json; } \
  | openssl dgst -sha256 -hmac "$DESIGNGEN_WEBHOOK_SECRET" -hex \
  | sed 's/^.*= //')"
test "$received" = "$expected"

Return quickly

Respond with a 2xx status after durable receipt. Delivery attempts time out after 10 seconds. Inspect and manually retry failed deliveries in the console; always make handlers idempotent.

Operate

Idempotency, lists, and limits

Design every create call for retries. Transport success does not replace reading the canonical resource, and a client timeout does not prove that creation failed.

Idempotency

Generation and vectorization creates require Idempotency-Key. Reusing a key with the same normalized request replays the original resource. Reusing it with different input returns 409.

List behavior

Use limit from 1–100 and optional status filtering. Read meta.hasMore and meta.nextCursor; only send a cursor when the API returns one.

Credit and concurrency controls

The server evaluates account balance, project/key credit caps, and active work before creation. Treat 402 and 429 as control responses, not transient network failures.

Retry policy

Retry a temporary concurrency 429 or retryable 5xx response with exponential backoff and jitter. A spend-limit 429 needs a limit or billing decision; do not loop on it. Do not automatically retry 400, 401, 403, 404/410, or a 409 idempotency conflict.

Lifecycle

Retention and deletion are explicit

Project assets follow the configured retention window. Metadata exposes status and expiry; authenticated file routes stop serving deleted or expired objects.
private → expiring → expired

Default project retention is 30 days and can be configured from 1–365 days at project creation. Read each asset's expiresAt; do not infer expiry from creation time.

Call POST /v1/assets/{assetId}/save before expiry to copy a selected asset into the owner's private Brand Library. Pass an optional brandId, description, and tags; otherwise the active brand is used. Only after the private Brand Library object and record exist does the developer asset become non-expiring. The action is idempotent and requires generations:create.

Deleting a generation or vectorization deletes its output assets and tombstones the job. Deleting an asset removes its private object. These actions are not a substitute for an application-level archival policy.

Saving is explicit

Generation completion never saves an output automatically. Choose the assets that should outlive project retention. The response returns the Brand Library brandId and assetId so your application can retain the durable link.

Diagnose

One error envelope

Error messages are safe for developers; codes are the stable branching surface. Store your own request context and the returned resource ID for support.
400invalid_requestFix shape, field constraints, URL, or reference roles.
401unauthorizedMissing, malformed, revoked, or unknown credential.
403forbidden / insufficient_scopePlan, project, environment, or key scope denies the operation.
402insufficient_creditsAdd credits or reduce the request before retrying.
404/410not_found / asset_expiredResource is outside the project, deleted, expired, or unknown.
409idempotency_conflictUse the original body or a new idempotency key.
429spend_limit_reached / concurrency_limit_reachedWait for capacity or adjust an authorized limit.
5xxinternal_errorRetry with backoff and the same idempotency key.
json · error envelope
{
  "success": false,
  "error": {
    "code": "idempotency_conflict",
    "message": "Idempotency key was already used with a different request"
  }
}

Reference

Versioning and changelog

The URL major version protects request and response compatibility. Additive fields and event types may appear within v1; integrations should ignore unknown response fields.

2026-09-01 · v1 foundation

  • Durable Ultra Max generation for prompt, reference, and screenshot workflows.
  • Private project assets and authenticated short-lived downloads.
  • Prompt Writer trace, vectorization beta, signed webhooks, and project-scoped keys.

General availability, pricing, and deprecation commitments are announced separately from additive documentation updates.

Make one development request, then inspect everything it created.

The console keeps prompt transformation, job state, billing, assets, and webhook delivery attached to the same durable record.

Open developer console