API Keys and Generate API
Create an API key and call
POST /api/creative/generateto generate images from a template in real time, without running a workflow.
What it is
The ConnectWyze generate API lets you render a template on demand by passing a set of variable values in a JSON request. The API returns a public image URL within seconds. No workflow or data source required.
API keys are workspace-scoped. Each key has a rate limit, an optional monthly cap, and can be restricted to specific templates. Keys exist in two modes: LIVE (production) and TEST ().
When you'd use it
- You have a product page and want to generate a share image dynamically when a visitor lands on it.
- You are building a CMS integration that creates a branded image for every new article.
- You want to trigger one-off renders from a script or CI pipeline.
- You are testing template variable combinations before running a full workflow.
Quick start (user)
Create an API key
- Go to Dashboard → API Keys (
/dashboard/creative/api-keys). - Click Create API Key.
- Enter a name (e.g.
Website – Product Cards). - Select a mode: LIVE for production use, TEST for development.
- Click Create. The full key is shown once — copy it immediately. It begins with
cw_live_orcw_test_. - The key appears in the table. The table shows only the 8-character prefix for security.
Restrict a key to specific templates (optional)
After creating a key, edit it to restrict which template IDs it may generate. Leave the template list empty to allow any template in the workspace.
Make your first API call
curl -X POST https://connectwyze.com/api/creative/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: cw_live_your_api_key" \
-d '{
"templateId": "clxxxxxxxxxxxxxx",
"variables": {
"product_name": "Air Max 90",
"price": "$120"
},
"format": "JPG",
"quality": 92
}'
Settings reference
API key fields
| Field | Type | Default | Description |
|---|---|---|---|
| Name | string | "Unnamed Key" |
Human-readable label. Not validated by the API. |
| Mode | LIVE | TEST |
LIVE |
Key mode flag. |
| Template IDs | string[] | [] (all) |
Restrict this key to specific template IDs. Empty array = all templates allowed. |
| Rate limit | integer | 100 |
Maximum requests per 60-second rolling window. |
| Monthly limit | integer | null | null |
Optional hard cap on requests per calendar month. null = unlimited. |
| Is active | boolean | true |
Disabled keys return 401. Use to temporarily block access without revoking. |
| Expires at | datetime | null | null |
Optional key expiry. Expired keys return 401. |
POST /api/creative/generate request body
| Field | Type | Required | Description |
|---|---|---|---|
templateId |
string | Yes | The template to render. Must belong to the key's workspace. |
variables |
object | No | Key-value pairs replacing template layer variables. Values are strings. |
focalPoints |
object | No | Override focal points for image layers. Format: { "layer_name": { "x": 0–100, "y": 0–100 } } |
format |
"PNG" | "JPG" | "WEBP" |
No | Output image format. Default: "PNG". JPG is 3× faster than PNG for most templates. |
quality |
integer 1–100 | No | Compression quality for JPG/WEBP. Default: 90. |
artboardId |
string | No | Render a specific artboard from a multi-size template. Omit to render the base artboard. |
Authentication
Pass the API key in one of two ways:
X-API-Key: cw_live_your_api_key
or
Authorization: Bearer cw_live_your_api_key
Response reference
200 — Success (fresh render)
{
"success": true,
"cached": false,
"imageUrl": "https://pub-xxxx.r2.dev/workspace/api/xxxx.jpg",
"width": 1080,
"height": 1080,
"format": "JPG",
"sizeBytes": 84321,
"generationMs": 1247
}
200 — Success (cache hit)
Identical inputs (same templateId + variables + focalPoints + format + quality + artboardId) within 24 hours return the previously generated URL without re-rendering. Cache hits do not consume credits.
{
"success": true,
"cached": true,
"imageUrl": "https://pub-xxxx.r2.dev/workspace/api/xxxx.jpg",
"width": 1080,
"height": 1080,
"format": "JPG",
"generationMs": 0
}
Response headers
| Header | Description |
|---|---|
X-RateLimit-Limit |
Requests allowed per 60-second window. |
X-RateLimit-Remaining |
Requests remaining in current window. |
X-RateLimit-Reset |
Unix timestamp (seconds) when the current window resets. |
X-Generation-Ms |
Time taken to render this image (0 for cache hits). |
Error responses
| Status | Error message | Cause |
|---|---|---|
401 |
API key required. Use X-API-Key header or Bearer token. |
No key provided. |
401 |
Invalid API key |
Key not found in database. |
401 |
API key has been revoked |
Key is inactive. |
401 |
API key has expired |
Key past its expiresAt date. |
402 |
Insufficient credits |
Workspace has no render credits available. Includes required, available, shortfall fields. |
403 |
Template not allowed for this API key |
templateId not in key's allowed list. |
404 |
Template not found |
templateId doesn't exist or is archived. |
429 |
Rate limit exceeded |
rateLimit per-minute cap hit. Includes retryAfter (seconds). |
400 |
Legacy v1 templates are no longer supported. Please recreate the template in the v2 editor. |
Template uses deprecated v1 canvas schema. |
500 |
Failed to generate image |
Render error on the server. |
Developer / API
JavaScript (fetch)
const response = await fetch('https://connectwyze.com/api/creative/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.CONNECTWYZE_API_KEY,
},
body: JSON.stringify({
templateId: 'clxxxxxxxxxxxxxx',
variables: {
headline: 'Summer Sale',
discount: '30% OFF',
},
format: 'JPG',
quality: 90,
}),
})
const data = await response.json()
if (!response.ok) {
if (response.status === 402) {
console.error(`Out of credits — shortfall: ${data.shortfall}`)
} else if (response.status === 429) {
// Retry after `data.retryAfter` seconds
console.error(`Rate limited. Retry in ${data.retryAfter}s`)
}
throw new Error(data.error)
}
console.log(data.imageUrl) // public URL, ready to use
Handling rate limits
The API uses an in-memory per-key sliding window (60 seconds). When you hit the limit, back off for retryAfter seconds from the 429 response body, or watch X-RateLimit-Remaining to throttle proactively.
Caching behaviour
The API caches results for 24 hours keyed on an MD5 hash of { templateId, variables, focalPoints, format, quality, artboardId }. Cache hits cost zero credits and return immediately. To force a fresh render, change any input value (e.g. append a timestamp to a variable).
Credits
Each fresh render (non-cache-hit) consumes creditsPerRender credits (default: 1 credit = $0.01). The API performs a pre-flight credit check before rendering. If the check passes but credits run out mid-render due to a concurrent workflow run, the image is delivered but the deduction is attempted on a best-effort basis.
Cache hits do not consume credits.
API discovery
GET /api/creative/generate returns the API documentation object with endpoint, field descriptions, and a cURL example.
ASCII diagram
Client request
│ POST /api/creative/generate
│ X-API-Key: cw_live_...
│ { templateId, variables, format }
▼
Key validation → rate limit check → credit pre-check
│
├── Cache hit? → return cached imageUrl (free)
│
▼
Render via Thor (or local Playwright fallback)
│ template-to-html.ts → headless Chromium → Sharp
▼
Upload to workspace storage (R2 / S3 / GCS)
│
▼
Deduct credits → log usage → return imageUrl
Troubleshooting
| Symptom | Fix |
|---|---|
Getting 401 Invalid API key even with correct key |
Key may be inactive or expired. Check status in Dashboard → API Keys. |
402 Insufficient credits on every request |
Workspace has run out of tier or purchased credits. Contact your workspace admin or [email protected] to add more. |
429 with retryAfter: 60 on a low-volume integration |
Default rate limit is 100 req/min. A workspace admin can raise it in the key settings. |
400 Legacy v1 templates error |
Open the template in the editor and resave — or recreate it from scratch. |
generationMs is very high (>10s) |
The render worker may be under load — retry after a short delay or contact support. |
| Image looks different from template editor | Fonts may be loading inconsistently — contact support with the template ID and a screenshot. |
Related
- Templates — build the template the API renders.
- Runs and creatives — for bulk generation, use workflows instead of per-item API calls.