Sign in

API Reference

Automate renders from any codebase, plugin, or pipeline. Upload an image, get a photorealistic render back.

Base https://rendercad.ai/backend/ Get API Token
# 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}'

Authentication

Bearer Token

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
All documented public 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.

Device Code Flow

For desktop apps, browser extensions, and CLIs that hand sign-in off to a browser.

1. Request code
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"}'
Response
{
  "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
}
2. Open the browser verification URL
Open verification_url in the user's browser.
The page already includes the device code in the link.
The user signs in there, and RENDERCAD authorizes automatically on that page.
3. Poll for completion over HTTP
curl "https://rendercad.ai/backend/auth.php?action=poll_device_code&code=ABCDEF"
Response (pending)
{
  "status": "pending",
  "message": "Waiting for user authorization"
}
Response (authorized)
{
  "status": "authorized",
  "api_token": "rendercad_xxxxxxxxxxxx",
  "message": "Authorization successful"
}
Response (expired)
{
  "status": "expired",
  "message": "Code has expired"
}
Error response
{
  "error": "Code parameter required"
}
Canonical bootstrap flow: request a device code, open verification_url, let the user sign in in the browser, then keep polling poll_device_code until the token is returned.
This flow uses HTTP polling, not WebSockets.
Authorized polls are retry-safe until the device-code window expires, so clients can recover from a missed first read.
Settings > API Tokens is for manual token management after bootstrap, not the primary app sign-in flow.

Discovery

Returns available models, capabilities, and credit costs.

Request
curl "https://rendercad.ai/backend/api_discovery.php?action=models" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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 and batch render requests. The current total_count is 43.

Request
curl "https://rendercad.ai/backend/api_discovery.php?action=conditions" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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.

Request
curl "https://rendercad.ai/backend/api_discovery.php?action=backgrounds" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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": 371
}

Returns the texture asset library for references objects with type: "material" and asset_kind: "texture".

Request
curl "https://rendercad.ai/backend/api_discovery.php?action=textures" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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.

Request
curl "https://rendercad.ai/backend/api_discovery.php?action=video_options" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "success": true,
  "video_options": {
    "defaults": {
      "video_mode": "single",
      "style": "preserve",
      "camera": "auto",
      "motion": "auto",
      "duration": 8,
      "resolution": "720p"
    },
    "styles": [{ "value": "preserve", "label": "Preserve" }],
    "camera_presets": [{ "value": "auto", "label": "Auto" }],
    "motion_presets": [{ "value": "auto", "label": "Auto" }],
    "durations": [{ "value": 8, "label": "8 seconds" }],
    "resolutions": [{ "value": "720p", "label": "720p" }]
  }
}

Image Rendering

create_job, presign_upload, finalize_job, and cancel require render-only or full-access. delete requires full-access. status and history require read-only or higher.

Request
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"
  }'
ParameterReqValuesDescription
source_urlNoURLExisting RENDERCAD asset URL to copy into the new job namespace. Omit to upload after job creation.
modelNoclassic proClassic = 1 token, Pro = 2 (default: classic)
qualityNostandard 4k4K requires Pro model
render_modeNopreserve creative freeformImage prompt mode
custom_instructionsNostring (max 1500)Additional AI instructions
conditionNostringCondition preset from GET /backend/api_discovery.php?action=conditions
background_styleNoauto white grey black gradient or custom:#RRGGBBSimple prompt-level background preset
referencesNoJSON arrayReference objects. Remote asset URLs are copied immediately; local files are returned as upload slots.
Response
{
  "success": true,
  "job_id": "render_abc123",
  "status": "uploading",
  "required_uploads": [
    { "slot": "input_main" }
  ]
}
If you already have a RENDERCAD asset URL, pass 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 80MB or smaller.
Request
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"}'
Response
{
  "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"
}
Upload the raw file yourself with PUT presigned_url using the matching Content-Type. Presign does not require a file-size field; the 80MB 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.
Request
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"}'
Response
{
  "success": true,
  "job_id": "render_abc123",
  "status": "pending",
  "queue_depth": 0,
  "queue_position": 0,
  "estimated_wait_seconds": 0
}
Request
curl "https://rendercad.ai/backend/render.php?action=status&job_id=render_abc123" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response (pending)
{
  "success": true,
  "job_id": "render_abc123",
  "status": "pending",
  "status_detail": "Queued...",
  "queue_depth": 3,
  "estimated_wait_seconds": 90
}
Response (completed)
{
  "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"
}
Response (failed)
{
  "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..

Returns paginated render history for the authenticated user. Supports page, limit, and filter=all|image|video.

Request
curl "https://rendercad.ai/backend/render.php?action=history&page=1&limit=50&filter=all" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total_count": 124,
    "total_pages": 3,
    "has_next": true
  }
}
History returns direct asset URLs in 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.
Request
curl -s -X POST "https://rendercad.ai/backend/render.php?action=cancel" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"render_abc123"}'
Response
{
  "success": true,
  "job_id": "render_abc123",
  "status": "canceled"
}
Only pending jobs can be canceled. Once a job has started processing, cancel returns 409 and there is no refund.
Request
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"}'
Response
{
  "success": true
}
Delete removes the job's files from storage but keeps the database record for account history and metrics. Active jobs in uploading, pending, or processing return 409; cancel pending jobs first or wait until processing finishes.

Video Generation

create_job, finalize_job, convert, and cancel require render-only or full-access. status requires read-only or higher.

Request
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": "1080p"
  }'
ParameterReqValuesDescription
image_urlYes*RENDERCAD asset URLSource image for single-image video mode
video_modeNosingle transition loopDefault: single
first_frame_urlYes**RENDERCAD asset URLRequired for video_mode=transition
last_frame_urlYes**RENDERCAD asset URLRequired for video_mode=transition
cameraNopresetCamera motion preset, default auto
motionNopresetProduct motion preset, default auto
styleNopreserve creativeCanonical video style preset
promptNostringExtra creative direction
durationNo4 6 8Seconds (default: 8)
resolutionNo720p 1080pDefault: 720p
crossfade_durationNo0.0-2.0Crossfade seconds for video_mode=loop
*Use 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.
Legacy aliases like exact and enhance are not supported. Use preserve or creative for style.

Token cost: duration + (resolution === '1080p' ? 1 : 0)

Response
{
  "success": true,
  "job_id": "uuid-format-id",
  "status": "uploading",
  "required_uploads": []
}
Request
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"}'
Response
{
  "success": true,
  "job_id": "uuid-format-id",
  "status": "pending",
  "tokens_used": 9,
  "queue_depth": 0,
  "queue_position": 0,
  "estimated_wait_seconds": 0
}
Request
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"
  }'
Response
{
  "success": true,
  "job_id": "vc_abc123",
  "status": "pending",
  "format": "gif"
}

Videos take 2-5 minutes. Poll every 10 seconds.

Request
curl "https://rendercad.ai/backend/video.php?action=status&job_id=uuid-format-id" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response (pending)
{
  "success": true,
  "job_id": "uuid-format-id",
  "status": "pending",
  "status_detail": "Queued...",
  "queue_depth": 2,
  "estimated_wait_seconds": 60
}
Response (completed)
{
  "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"
}
Response (failed)
{
  "success": true,
  "job_id": "uuid-format-id",
  "status": "failed",
  "status_detail": "Failed",
  "error": "Generation failed",
  "completed_at": "2026-02-11T10:04:22Z"
}
Request
curl -s -X POST "https://rendercad.ai/backend/video.php?action=cancel" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"uuid-format-id"}'
Response
{
  "success": true,
  "job_id": "uuid-format-id",
  "status": "canceled"
}
Only pending video jobs can be canceled. Once a job has started processing, cancel returns 409 and there is no refund.

Status Updates (Polling)

/backend/sse_status.php was removed. Use polling instead:

ResourceEndpointInterval
ImagesGET /backend/render.php?action=status&job_id=...2 seconds
VideosGET /backend/video.php?action=status&job_id=...10 seconds
JavaScript example
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;
}

Account

Request
curl "https://rendercad.ai/backend/auth.php?action=check" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "success": true,
  "authenticated": true,
  "token_valid": true,
  "csrf_token": "csrf_...",
  "token_costs": {
    "classic": 1,
    "pro": 2,
    "4k_upgrade": 2
  },
  "user": {
    "id": 123,
    "email": "user@example.com",
    "subscription_plan": "professional",
    "monthly_render_limit": 120,
    "monthly_renders_used": 45,
    "grant_tokens_remaining": 12,
    "pooled_tokens_remaining": 87
  }
}
If no credentials are supplied and there is no active first-party session, this endpoint returns 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.

Request
curl "https://rendercad.ai/backend/auth.php?action=usage" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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.

Request
curl "https://rendercad.ai/backend/auth.php?action=plan_info" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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
}

Token Management

Returns all API tokens for the authenticated user.

Request
curl "https://rendercad.ai/backend/auth.php?action=get_api_tokens" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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
}
Request
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","scope":"full-access"}'
ParameterReqDescription
token_nameYesDisplay name (max 100 chars)
scopeNoread-only, render-only, or full-access (default: full-access)

Token Scopes

ScopePermissions
read-onlyCheck auth, view usage, view plan info, call discovery endpoints, list tokens, list webhooks, and get history
render-onlyEverything in read-only, plus request upload URLs, submit/cancel renders, and submit/cancel video jobs
full-accessAll actions, including token create/revoke/rename and webhook register/delete
Response
{
  "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."
}
Token is shown only once in the response. Save it immediately.
Request
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}'
Response
{
  "success": true,
  "message": "API token revoked successfully"
}
Request
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"}'
Response
{
  "success": true,
  "message": "API token renamed successfully"
}

Webhooks

Real-time notifications. Max 5 per account. Register/delete require full-access scope; list requires read-only or higher.

Request
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"]
  }'
ParameterReqDescription
urlYesHTTPS webhook endpoint (must be HTTPS)
eventsYesArray: render.completed, render.failed, video.completed, video.failed, credits.exhausted
Response
{
  "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"
}
The signing secret is shown only once when the webhook is created.

Returns all registered webhooks with status and delivery stats.

Request
curl "https://rendercad.ai/backend/webhooks.php?action=list" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "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
    }
  ]
}
Request
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}'
Response
{
  "success": true,
  "message": "Webhook deleted"
}

Webhook Delivery

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.

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.

Delivery headers
Content-Type: application/json
User-Agent: RENDERCAD-Webhooks/1.0
X-Webhook-Signature: sha256=...
X-Webhook-Event: render.completed
X-Webhook-Delivery: <delivery_id>

Payload: render.completed

Payload
{
  "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"
}

Payload: video.completed

Payload
{
  "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"
}
Video conversion completion webhooks also include format.

Payload: render.failed

Payload
{
  "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"
}
For render.failed, error is the same display-safe failure text returned by render status.

Payload: video.failed

Payload
{
  "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"
}

Payload: credits.exhausted

Payload
{
  "event_type": "credits.exhausted",
  "delivery_id": "12347",
  "timestamp": "2026-02-11T15:00:00Z",
  "user_id": "user_xyz",
  "credits_used": 120,
  "credits_limit": 120,
  "billing_cycle_end": "2026-02-28"
}
Webhook list endpoints expose delivery stats, not per-attempt history. A permanently failed delivery increments failure_count; a successful later delivery resets it to 0.

Token Costs

Image Rendering

ModelQualityTokens
ClassicStandard1
ProStandard2
Pro4K4

Video Generation

Duration720p1080p
4 seconds45
6 seconds67
8 seconds89

Errors & Rate Limits

CodeMeaning
200Success
400Bad request / validation error
401Missing required auth or invalid supplied auth credentials
403Forbidden / not authorized (scope insufficient)
404Unknown action or missing resource
409State conflict, including non-cancelable jobs
405Method not allowed
415Content-Type must be application/json for documented public POST endpoints
422Semantic validation error (for example oversized Pro input)
429Rate limit, credit exhaustion, or queue/capacity limit
500Server error
Error format
{
  "error": "Error message here"
}
All documented public endpoints return a top-level error string on non-2xx responses.

Rate Limits

EndpointLimit
Render submit, presign upload, history, delete, cancelNo request-rate limit. These endpoints can still return 429 for credit exhaustion, concurrency, or queue capacity.
Batch render30 requests/hour
Video generate10 requests / 5 minutes
Video convert20 requests / 5 minutes
Status polling120 requests/minute combined across render and video status endpoints
Device code request10 requests/hour
Device code poll60 requests / 10 minutes
Device code authorize5 requests/hour
Auth status, usage, plan infoNo request-rate limit
Token list120 requests/hour
Token create, revoke, rename10 requests/hour
Discovery endpoints60 requests/hour
Webhook list60 requests/hour
Webhook register and delete10 requests/hour
Limited endpoints return X-RateLimit-Endpoint, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on 429.