Automate renders from any codebase, plugin, or pipeline. Send a CAD screenshot to the render endpoint, get a photorealistic render back. API access is included on Starter plans and up - see pricing.
# Quick start: create job, upload, finalize, poll
JOB=$(curl -s -X POST "https://rendercad.ai/backend/render.php?action=create_job" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"pro","quality":"standard","render_mode":"preserve","background_style":"auto","condition":"auto"}')
JOB_ID=$(echo "$JOB" | jq -r '.job_id')
UPLOAD=$(curl -s -X POST "https://rendercad.ai/backend/render.php?action=presign_upload" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"job_id\":\"$JOB_ID\",\"slot\":\"input_main\",\"content_type\":\"image/jpeg\"}")
curl -s -X PUT "$(echo "$UPLOAD" | jq -r '.presigned_url')" \
-H "Content-Type: image/jpeg" \
--data-binary "@photo.jpg" > /dev/null
RENDER=$(curl -s -X POST "https://rendercad.ai/backend/render.php?action=finalize_job" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"job_id\":\"$JOB_ID\"}")
while true; do
STATUS=$(curl -s "https://rendercad.ai/backend/render.php?action=status&job_id=$JOB_ID" \
-H "Authorization: Bearer $TOKEN")
STATE=$(echo "$STATUS" | jq -r '.status')
[ "$STATE" != "pending" ] && [ "$STATE" != "processing" ] && break
sleep 2
done
echo "$STATUS" | jq '{status,output_url,asset_url,error_message}'
Include your API token in the Authorization header. Apps usually obtain their first token through the device-code browser flow below. Manage long-lived tokens in Settings > API Tokens.
Authorization: Bearer rendercad_xxxxxxxxxxxx
POST endpoints are JSON-only. If you send Authorization or X-Auth-Token and it is invalid, the API returns 401 and does not fall back to cookie/session auth.For desktop apps, browser extensions, and CLIs that hand sign-in off to a browser.
curl -s -X POST "https://rendercad.ai/backend/auth.php?action=request_device_code" \ -H "Content-Type: application/json" \ -d '{"app_name":"RENDERCAD Browser Extension","app_type":"browser-extension","app_version":"1.0.0"}'
{
"success": true,
"code": "ABCDEF",
"verification_url": "https://rendercad.ai/auth_device.html?code=ABCDEF&app_name=RENDERCAD%20Browser%20Extension&app_type=browser-extension&app_version=1.0.0",
"expires_in": 600,
"poll_interval": 3
}
Open verification_url in the user's browser.
The page already includes the device code in the link.
The user signs in there, reviews the requesting app, and clicks Authorize.
curl "https://rendercad.ai/backend/auth.php?action=poll_device_code&code=ABCDEF"
{
"status": "pending",
"message": "Waiting for user authorization"
}
{
"status": "authorized",
"api_token": "rendercad_xxxxxxxxxxxx",
"message": "Authorization successful"
}
{
"status": "expired",
"message": "Code has expired"
}
{
"error": "Code parameter required"
}
verification_url, let the user sign in and explicitly authorize the app, then keep polling poll_device_code until the token is returned.Returns available models, capabilities, and credit costs.
curl "https://rendercad.ai/backend/api_discovery.php?action=models" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"models": [
{
"id": "classic",
"name": "Fast",
"description": "Quick renders with good quality",
"cost_credits": 1,
"supports_4k": false,
"supports_references": false,
"max_references": 0
},
{
"id": "pro",
"name": "Realistic",
"description": "High-quality photorealistic renders",
"cost_credits": 2,
"supports_4k": true,
"supports_references": true,
"max_references": 6
}
],
"quality_tiers": [
{
"id": "standard",
"name": "HD",
"resolution": "1024x1024",
"additional_cost": 0
},
{
"id": "4k",
"name": "4K",
"resolution": "4096x4096",
"additional_cost": 2,
"requires_model": "pro"
}
],
"render_modes": [
{
"id": "preserve",
"name": "Exact Mode"
},
{
"id": "creative",
"name": "Enhance Mode"
},
{
"id": "freeform",
"name": "Freeform Mode"
}
]
}
Returns all valid condition values accepted by image render requests. The current total_count is 43.
curl "https://rendercad.ai/backend/api_discovery.php?action=conditions" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"conditions": [
{"value": "auto", "label": "Auto (no condition)", "category": null},
{"value": "pristine", "label": "Pristine", "category": "Clean"},
{"value": "factory-new", "label": "Factory New", "category": "Clean"},
{"value": "snow-covered", "label": "Snow-Covered", "category": "Environmental Coverage"}
],
"total_count": 43,
"categories": ["Clean", "Surface", "Damage", "Age", "Wear", "Structural", "Moisture & Temperature", "Extreme States", "Environmental Coverage"]
}
Returns the background asset library for references objects with type: "background". These asset IDs are not valid background_style values.
curl "https://rendercad.ai/backend/api_discovery.php?action=backgrounds" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"backgrounds": [
{
"id": "24charpublicid",
"name": "Modern White House with Pool and Garden",
"category": "exterior",
"thumb_url": "https://renders.rendercad.ai/backgrounds/thumbs/exterior-3d-rendering-exterior-modern-house-in-minimal-architecture.webp"
}
],
"total_count": 1334
}
Returns the texture asset library for references objects with type: "material" and asset_kind: "texture".
curl "https://rendercad.ai/backend/api_discovery.php?action=textures" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"textures": [
{
"id": "24charpublicid",
"name": "Brushed Metal",
"category": "metal",
"thumb_url": "https://renders.rendercad.ai/textures/thumbs/metal-brushed-metal-1.webp"
}
],
"total_count": 2942
}
Returns valid video preset values, defaults, durations, and resolutions for video generation requests.
curl "https://rendercad.ai/backend/api_discovery.php?action=video_options" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"video_options": {
"defaults": {
"video_mode": "single",
"style": "preserve",
"camera": "auto",
"motion": "auto",
"duration": 8,
"resolution": "720p"
},
"styles": [
{ "value": "preserve", "label": "Exact" },
{ "value": "creative", "label": "Enhance" }
],
"camera_presets": [{ "value": "auto", "label": "Auto" }],
"motion_presets": [{ "value": "auto", "label": "Auto" }],
"durations": [
{ "value": 4, "label": "4s" },
{ "value": 6, "label": "6s" },
{ "value": 8, "label": "8s" }
],
"resolutions": [
{ "value": "720p", "label": "720p" }
]
}
}
create_job, presign_upload, and finalize_job require render-only or full-access. delete requires full-access. status and history require read-only or higher.
curl -s -X POST "https://rendercad.ai/backend/render.php?action=create_job" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "source_url":"https://renders.rendercad.ai/abc123_input", "model":"pro", "quality":"standard", "render_mode":"preserve", "background_style":"auto", "condition":"auto", "custom_instructions":"Make it more modern" }'
| Parameter | Req | Values | Description |
|---|---|---|---|
source_url | No | URL | Existing RENDERCAD asset URL to copy into the new job namespace. Omit to upload after job creation. |
model | No | classic pro | Classic = 1 token, Pro = 2 (default: classic) |
quality | No | standard 4k | 4K requires Pro model |
render_mode | No | preserve creative freeform | Image prompt mode |
custom_instructions | No | string (max 1500) | Additional AI instructions |
condition | No | string | Condition preset from GET /backend/api_discovery.php?action=conditions |
background_style | No | auto white grey black gradient or custom:#RRGGBB | Simple prompt-level background preset |
references | No | JSON array | Reference objects. Remote asset URLs are copied immediately; local files are returned as upload slots. |
request_id | No | string (max 80, A-Za-z0-9_-) | Idempotency key. Retrying create_job with the same request_id returns the existing job instead of creating and charging a new one. Use a fresh value per intended job. |
{
"success": true,
"job_id": "render_abc123",
"status": "uploading",
"required_uploads": [
{ "slot": "input_main" }
]
}
source_url and required_uploads can be empty. If uploads are required, call presign_upload for each slot, upload the bytes yourself, then call finalize_job. Uploaded images are validated during finalize and must be 50MB or smaller.curl -s -X POST "https://rendercad.ai/backend/render.php?action=presign_upload" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"render_abc123","slot":"input_main","content_type":"image/jpeg"}'
{
"success": true,
"presigned_url": "https://...signed-put-url...",
"asset_url": "https://renders.rendercad.ai/abc123_input",
"slot": "input_main",
"index": null,
"expires_in": 300,
"cache_control": "public, max-age=31536000, immutable"
}
PUT presigned_url using the matching Content-Type. Presign does not require a file-size field; the 50MB image limit is enforced when finalize_job validates the uploaded object. The returned asset_url is the canonical RENDERCAD asset URL for that uploaded slot.curl -s -X POST "https://rendercad.ai/backend/render.php?action=finalize_job" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"render_abc123"}'
{
"success": true,
"job_id": "render_abc123",
"status": "pending",
"queue_depth": 0,
"queue_position": 0,
"estimated_wait_seconds": 0
}
curl "https://rendercad.ai/backend/render.php?action=status&job_id=render_abc123" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"job_id": "render_abc123",
"status": "pending",
"status_detail": "Queued...",
"queue_depth": 3,
"estimated_wait_seconds": 90
}
{
"success": true,
"job_id": "render_abc123",
"status": "completed",
"status_detail": null,
"output_url": "https://rendercad.ai/backend/serve_render.php?id=render_abc123",
"asset_url": "https://renders.rendercad.ai/abc123",
"input_url": "https://renders.rendercad.ai/abc123_input",
"completed_at": "2026-02-11T10:04:22Z"
}
{
"success": true,
"job_id": "render_abc123",
"status": "failed",
"status_detail": "Failed",
"error_message": "Content policy violation",
"completed_at": "2026-02-11T10:04:22Z"
}
error_message is display-safe text. Transient infrastructure failures may return Rendering is overloaded. You were not charged. Please try again later., Upload did not finish. You were not charged. Please try again., Render did not start. You were not charged. Please try again., or Rendering timed out. You were not charged. Please try again..job_id accepts up to 100 comma-separated ids (job_id=render_a,render_b). The response becomes {"success": true, "jobs": [...]} with one entry per id in the same shapes as above; unknown ids get {"success": false, "job_id": "...", "error_code": "job_not_found"} without failing the request. A single id keeps the flat response shown above.Returns paginated render history for the authenticated user. Supports page, limit, filter=all|image|video, search (matches against the render prompt), favorites=1 (favorited renders only), folder (exact folder name), date_from / date_to (YYYY-MM-DD, inclusive), and sort=newest|oldest. The response includes a folders array listing your folder names.
curl "https://rendercad.ai/backend/render.php?action=history&page=1&limit=50&filter=all" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"renders": [
{
"job_id": "render_abc123",
"status": "completed",
"render_mode": "creative",
"model": "pro",
"quality_tier": "4k",
"input_url": "https://renders.rendercad.ai/abc123_input",
"output_url": "https://renders.rendercad.ai/abc123",
"created_at": "2026-02-11T10:00:00Z",
"completed_at": "2026-02-11T10:04:22Z",
"days_to_deletion": 87,
"label": "Hero shot v2",
"is_favorite": true,
"folder": "Client A"
}
],
"folders": ["Client A"],
"pagination": {
"page": 1,
"limit": 50,
"total_count": 124,
"total_pages": 3,
"has_next": true
}
}
output_url. The status endpoint returns an authenticated proxy output_url plus direct asset_url. For video renders, consume video_settings as the canonical settings object; background_style is image-only and will be null on video rows.curl -s -X POST "https://rendercad.ai/backend/render.php?action=delete" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"render_abc123"}'
{
"success": true
}
uploading, pending, or processing return 409; wait until the job finishes.Sets a display label on a render (max 120 characters). Send an empty label to clear it. Labels appear in history responses and the History page.
curl -s -X POST "https://rendercad.ai/backend/render.php?action=set_label" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"render_abc123","label":"Hero shot v2"}'
{
"success": true,
"job_id": "render_abc123",
"label": "Hero shot v2"
}
render-only or full-access. Unknown or foreign job ids return 404 with error_code: "job_not_found".Marks or unmarks a render as a favorite. Favorited renders can be filtered in history with favorites=1. To organize renders into folders instead, use action=set_folder with {"job_id": "...", "folder": "Client A"} (empty folder removes it; assigning a new name creates the folder implicitly).
curl -s -X POST "https://rendercad.ai/backend/render.php?action=set_favorite" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"render_abc123","favorite":true}'
{
"success": true,
"job_id": "render_abc123",
"is_favorite": true
}
render-only or full-access. Unknown or foreign job ids return 404 with error_code: "job_not_found".create_job, finalize_job, and convert require render-only or full-access. status requires read-only or higher.
curl -s -X POST "https://rendercad.ai/backend/video.php?action=create_job" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "image_url": "https://renders.rendercad.ai/abc123.jpg", "camera": "orbit", "motion": "hero-spin", "style": "preserve", "prompt": "Slow dramatic product reveal", "duration": 8, "resolution": "720p" }'
| Parameter | Req | Values | Description |
|---|---|---|---|
image_url | Yes* | RENDERCAD asset URL | Source image for single-image video mode |
video_mode | No | single transition loop | Default: single |
first_frame_url | Yes** | RENDERCAD asset URL | Required for video_mode=transition |
last_frame_url | Yes** | RENDERCAD asset URL | Required for video_mode=transition |
camera | No | preset | Camera motion preset, default auto |
motion | No | preset | Product motion preset, default auto |
style | No | preserve creative | Canonical video style preset |
prompt | No | string | Extra creative direction |
duration | No | 4 6 8 | Seconds (default: 8) |
resolution | No | 720p | Default: 720p |
crossfade_duration | No | 0.0-2.0 | Crossfade seconds for video_mode=loop |
request_id | No | string (max 80, A-Za-z0-9_-) | Idempotency key. Retrying create_job with the same request_id returns the existing job instead of creating and charging a new one. Image and video jobs use separate request_id namespaces. |
image_url for single and loop videos. **Use first_frame_url and last_frame_url for transition videos. Submit public RENDERCAD asset URLs when you already have them. If the response includes upload slots, call POST /backend/render.php?action=presign_upload for each slot, upload the bytes yourself, then call POST /backend/video.php?action=finalize_job. Preset values are discoverable via GET /backend/api_discovery.php?action=video_options.exact and enhance are not supported. Use preserve or creative for style.Token cost: duration * 2
{
"success": true,
"job_id": "uuid-format-id",
"status": "uploading",
"required_uploads": []
}
curl -s -X POST "https://rendercad.ai/backend/video.php?action=finalize_job" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"job_id":"uuid-format-id"}'
{
"success": true,
"job_id": "uuid-format-id",
"status": "pending",
"tokens_used": 9,
"queue_depth": 0,
"queue_position": 0,
"estimated_wait_seconds": 0
}
curl -s -X POST "https://rendercad.ai/backend/video.php?action=convert" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://renders.rendercad.ai/video_abc123.mp4", "format": "gif" }'
{
"success": true,
"job_id": "vc_abc123",
"status": "pending",
"format": "gif"
}
Videos take 2-5 minutes. Poll every 10 seconds.
curl "https://rendercad.ai/backend/video.php?action=status&job_id=uuid-format-id" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"job_id": "uuid-format-id",
"status": "pending",
"status_detail": "Queued...",
"queue_depth": 2,
"estimated_wait_seconds": 60
}
{
"success": true,
"job_id": "uuid-format-id",
"status": "completed",
"status_detail": null,
"video_url": "https://renders.rendercad.ai/video_abc123.mp4",
"completed_at": "2026-02-11T10:04:22Z"
}
{
"success": true,
"job_id": "uuid-format-id",
"status": "failed",
"status_detail": "Failed",
"error": "Generation failed",
"completed_at": "2026-02-11T10:04:22Z"
}
/backend/sse_status.php was removed. Use polling instead:
| Resource | Endpoint | Interval |
|---|---|---|
| Images | GET /backend/render.php?action=status&job_id=... | 2 seconds |
| Videos | GET /backend/video.php?action=status&job_id=... | 10 seconds |
async function pollVideoStatus(jobId) { const res = await fetch( `/backend/video.php?action=status&job_id=${encodeURIComponent(jobId)}`, { credentials: 'include' } ); const data = await res.json(); return data.status; }
curl "https://rendercad.ai/backend/auth.php?action=check" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"authenticated": true,
"token_valid": true,
"csrf_token": "csrf_...",
"token_costs": {
"classic": 1,
"pro": 2,
"pro_4k": 4,
"4k_upgrade": 2,
"video": 4
},
"user": {
"id": "user_abc123",
"email": "user@example.com",
"subscription_plan": "professional",
"monthly_render_limit": 120,
"monthly_renders_used": 45,
"grant_tokens_remaining": 12,
"pooled_tokens_remaining": 87
}
}
200 with {"success":false,"authenticated":false,"token_valid":false}. If Authorization or X-Auth-Token is present but invalid, it returns 401 with the same flags plus error.Detailed usage statistics for the current billing cycle.
curl "https://rendercad.ai/backend/auth.php?action=usage" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"monthly_limit": 120,
"monthly_used": 45,
"monthly_remaining": 75,
"grant_tokens_remaining": 12,
"pooled_tokens_remaining": 87,
"pending_renders": 2,
"billing_cycle_start": "2026-02-01",
"billing_cycle_end": "2026-02-28",
"avg_render_times": {
"avg_image_seconds": 18,
"avg_video_seconds": 77
}
}
Returns detailed subscription plan and billing information.
curl "https://rendercad.ai/backend/auth.php?action=plan_info" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"plan_name": "Professional",
"plan_code": "professional",
"plan_id": "professional",
"monthly_credit_limit": 120,
"credits_used_this_month": 45,
"credits_remaining": 75,
"grant_tokens_remaining": 12,
"pooled_tokens_remaining": 87,
"billing_cycle_start": "2026-02-01",
"billing_cycle_end": "2026-02-28",
"next_reset_date": "2026-03-01",
"subscription_status": "active",
"price_cents": 4999,
"cancel_at_period_end": false,
"cancel_at": null
}
Returns all API tokens for the authenticated user.
curl "https://rendercad.ai/backend/auth.php?action=get_api_tokens" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"tokens": [
{
"id": 123,
"token_name": "My App",
"scope": "full-access",
"created_at": "2026-02-11T10:00:00Z",
"last_used_at": "2026-02-11T14:25:10Z",
"usage_count": 42,
"is_active": true
}
],
"max_tokens": 10
}
curl -s -X POST "https://rendercad.ai/backend/auth.php?action=create_api_token" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"token_name":"My App"}'
| Parameter | Req | Description |
|---|---|---|
token_name | Yes | Display name (max 100 chars) |
scope response field remains for compatibility and does not grant additional access.{
"success": true,
"message": "API token created successfully",
"token": "rendercad_xxxxxxxxxxxx",
"token_data": {
"id": 123,
"token_name": "My App",
"scope": "full-access",
"created_at": "2026-02-11T10:00:00Z",
"last_used_at": null,
"usage_count": 0
},
"warning": "Save this token now. You will not be able to see it again."
}
curl -s -X POST "https://rendercad.ai/backend/auth.php?action=revoke_api_token" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"token_id":123}'
{
"success": true,
"message": "API token revoked successfully"
}
curl -s -X POST "https://rendercad.ai/backend/auth.php?action=rename_api_token" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"token_id":123,"new_name":"Production CLI"}'
{
"success": true,
"message": "API token renamed successfully"
}
Real-time notifications. Max 5 per account. Register/delete require full-access scope; list requires read-only or higher.
curl -s -X POST "https://rendercad.ai/backend/webhooks.php?action=register" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-domain.com/webhook", "events": ["render.completed", "render.failed", "video.completed", "video.failed"] }'
| Parameter | Req | Description |
|---|---|---|
url | Yes | HTTPS webhook endpoint (must be HTTPS) |
events | Yes | Array: render.completed, render.failed, video.completed, video.failed, credits.low, credits.exhausted |
{
"success": true,
"id": 123,
"url": "https://your-domain.com/webhook",
"events": ["render.completed", "render.failed"],
"status": "active",
"secret": "whsec_...",
"created_at": "2026-02-11T10:30:00Z"
}
Returns all registered webhooks with status and delivery stats.
curl "https://rendercad.ai/backend/webhooks.php?action=list" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"webhooks": [
{
"id": 123,
"url": "https://your-domain.com/webhook",
"events": ["render.completed", "render.failed", "video.completed", "video.failed"],
"status": "active",
"created_at": "2026-02-11T10:30:00Z",
"last_triggered_at": "2026-02-11T14:25:10Z",
"last_success_at": "2026-02-11T14:25:10Z",
"failure_count": 0
}
]
}
curl -s -X POST "https://rendercad.ai/backend/webhooks.php?action=delete" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id":123}'
{
"success": true,
"message": "Webhook deleted"
}
curl -s -X POST "https://rendercad.ai/backend/webhooks.php?action=test" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id":123}'
{
"success": true,
"delivered": true,
"http_code": 200,
"error": null
}
webhook.test event to your endpoint synchronously so you can verify reachability and signature validation without spending a render. The delivery is recorded in the delivery log.curl "https://rendercad.ai/backend/webhooks.php?action=deliveries&id=123" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"success": true,
"webhook_id": 123,
"deliveries": [
{
"delivery_id": "uuid",
"event_type": "render.completed",
"outcome": "succeeded",
"attempts": 1,
"http_code": 200,
"error": null,
"delivered_at": "2026-07-02T12:00:00+00:00"
}
]
}
outcome is succeeded, retry_scheduled, or failed (all retries exhausted).Webhooks are delivered asynchronously as POST requests. Delivery uses one immediate attempt plus retries after 1m, 5m, and 15m if your endpoint does not return 2xx. Each attempt times out after 8s.
Verify signatures with hash_hmac('sha256', raw_json_body, webhook_secret) and compare the hex digest to the value after sha256= in X-Webhook-Signature.
Content-Type: application/json User-Agent: RENDERCAD-Webhooks/1.0 X-Webhook-Signature: sha256=... X-Webhook-Event: render.completed X-Webhook-Delivery: <delivery_id>
{
"event_type": "render.completed",
"delivery_id": "12345",
"timestamp": "2026-02-11T14:25:10Z",
"job_id": "render_abc123",
"status": "completed",
"output_url": "https://renders.rendercad.ai/output_abc123.jpg",
"processing_time_ms": 4200,
"completed_at": "2026-02-11T14:25:10Z"
}
{
"event_type": "video.completed",
"delivery_id": "12346",
"timestamp": "2026-02-11T14:30:00Z",
"job_id": "video_uuid",
"status": "completed",
"video_url": "https://renders.rendercad.ai/video_abc123.mp4",
"processing_time_ms": 95000,
"completed_at": "2026-02-11T14:30:00Z"
}
format.{
"event_type": "render.failed",
"delivery_id": "12347",
"timestamp": "2026-02-11T14:31:00Z",
"job_id": "render_def456",
"status": "failed",
"error": "Provider rejected the input image",
"input_url": "https://renders.rendercad.ai/input_def456.jpg",
"completed_at": "2026-02-11T14:31:00Z"
}
render.failed, error is the same display-safe failure text returned by render status.{
"event_type": "video.failed",
"delivery_id": "12348",
"timestamp": "2026-02-11T14:32:00Z",
"job_id": "video_ghi789",
"status": "failed",
"error": "Generation timed out",
"input_url": "https://renders.rendercad.ai/input_ghi789.jpg",
"completed_at": "2026-02-11T14:32:00Z"
}
{
"event_type": "credits.low",
"delivery_id": "uuid",
"timestamp": "2026-07-02T15:00:00Z",
"remaining_tokens": 48,
"monthly_limit": 500,
"low_threshold": 50
}
credits.low fires once per billing cycle when a job submission drops your combined remaining balance (monthly plus gifted credits) to 10% of the monthly limit or below. credits.exhausted fires when the balance reaches zero. Both fire at job creation time, not on a schedule.failure_count; a successful later delivery resets it to 0.| Model | Quality | Tokens |
|---|---|---|
| Classic | Standard | 1 |
| Pro | Standard | 2 |
| Pro | 4K | 4 |
| Duration | 720p |
|---|---|
| 4 seconds | 8 |
| 6 seconds | 12 |
| 8 seconds | 16 |
| Code | Meaning |
|---|---|
200 | Success |
400 | Bad request / validation error |
401 | Missing required auth or invalid supplied auth credentials |
403 | Forbidden / not authorized (scope insufficient) |
404 | Unknown action or missing resource |
405 | Method not allowed |
409 | State conflict, such as finalizing or deleting a job in the wrong state |
415 | Content-Type must be application/json for documented public POST endpoints |
422 | Semantic validation error (for example oversized Pro input) |
429 | Rate limit, credit exhaustion, or queue/capacity limit |
500 | Server error |
{
"error": "Error message here",
"error_code": "machine_readable_code"
}
error string on non-2xx responses, plus a stable snake_case error_code for programmatic handling. Match on error_code, not on error text - messages may be reworded. Common codes: authentication_required, invalid_api_token, invalid_request, job_not_found, job_not_finalizable, job_conflict, insufficient_credits, active_render_limit_reached, server_at_capacity, payload_too_large, internal_error.| Endpoint | Limit |
|---|---|
| Render submit, presign upload, history, delete | No request-rate limit. These endpoints can still return 429 for credit exhaustion, concurrency, or queue capacity. |
| Video generate | 10 requests / 5 minutes |
| Video convert | 20 requests / 5 minutes |
| Status polling | 120 requests/minute combined across render and video status endpoints |
| Device code request | 10 requests/hour |
| Device code poll | 60 requests / 10 minutes |
| Device code authorize | 5 requests/hour |
| Auth status, usage, plan info | No request-rate limit |
| Token list | 120 requests/hour |
| Token create, revoke, rename | 10 requests/hour |
| Discovery endpoints | 60 requests/hour |
| Webhook list | 120 requests/hour |
| Webhook register and delete | 10 requests/hour |
X-RateLimit-Endpoint, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on 429.