Start
Five-minute quickstart
- 01
Create a project
Use a development project to isolate keys, jobs, assets, and limits.
- 02
Issue a scoped key
Select generations:create, generations:read, and assets:read. Copy the secret once.
- 03
Queue the job
Send an Idempotency-Key. A 202 response means the durable record exists.
- 04
Poll and download
Respect Retry-After, wait for completed, then follow the authenticated file redirect.
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 "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.pngFoundation
Authentication and projects
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
/v1/developer/projectsCreate a project from an authenticated console session.
/v1/developer/api-keysCreate a project-bound key; the secret is returned once.
/v1/developer/api-keys/{keyId}Revoke a key without removing its historical usage.
Inputs
Private assets
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.
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
preserveUse your prompt without creative rewriting.
autoApply restrained improvements when they clarify the request.
enhanceActively structure composition, production intent, and reference roles.
Locked text is an instruction, not OCR
lockedText for exact copy that must be preserved. Always inspect final artwork before production.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
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.
// 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
Prompt to design
Do not include references. Choose preserve, auto, or enhance and describe standalone artwork—not a shirt mockup.
-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"
}
}'Role-aware references
Provide 1–14 unique assets. Assign each one a role: product, logo, style, layout, background, or source.
{
"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 artwork
Provide exactly one reference with the source role. Supporting references may use the remaining roles.
{
"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
Vectorization is a named beta
Poll GET /v1/vectorizations/{id}. After completion, download a requested format from /files/{format}.
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
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
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
# 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.
queuedAccepted and waiting for a worker.
runningIn progress; inspect stage for orientation.
awaiting_inputA current question needs a scoped answer or attachment.
awaiting_approvalA runtime-supplied decision needs an explicit choice.
completedOutput asset IDs and authenticated file routes are available.
blockedStopped by a safety or policy decision.
failedInspect error and retryable before deciding to resubmit.
cancelledCancelled 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 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"]
}'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);
}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"])
# 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
Operate
Idempotency, lists, and limits
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
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
brandId and assetId so your application can retain the durable link.Diagnose
One error envelope
invalid_requestFix shape, field constraints, URL, or reference roles.unauthorizedMissing, malformed, revoked, or unknown credential.forbidden / insufficient_scopePlan, project, environment, or key scope denies the operation.insufficient_creditsAdd credits or reduce the request before retrying.not_found / asset_expiredResource is outside the project, deleted, expired, or unknown.idempotency_conflictUse the original body or a new idempotency key.spend_limit_reached / concurrency_limit_reachedWait for capacity or adjust an authorized limit.internal_errorRetry with backoff and the same idempotency key.{
"success": false,
"error": {
"code": "idempotency_conflict",
"message": "Idempotency key was already used with a different request"
}
}Reference
Versioning and changelog
Contract sources
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