Tenant API
Render video through the Decent Render network via a simple REST API. Standard Remotion bundle + inputProps.
Authentication
All requests require a bearer token (API key):
Authorization: Bearer <your-api-key>Create keys at decent-render.farm/api-keys. Keys are shown once at creation.
POST /api/v1/renders
Enqueue a render. Required scope: render:enqueue
Body
{
"bundleSha256": "<sha256 of your Remotion bundle>",
"inputProps": {},
"compositionWidth": 1920,
"compositionHeight": 1080,
"fps": 30,
"durationFrames": 90,
"codec": "h264",
"kind": "standard"
}Response (202)
{
"renderId": "job-render-...",
"status": "pending",
"taskId": "render-...",
"creditsReserved": 5
}GET /api/v1/renders/:id
Check render status. Required scope: render:read
Response
{
"renderId": "job-render-...",
"status": "complete",
"progress": 1,
"outputUrl": "https://...",
"creditsReserved": 5,
"creditsSettled": 5,
"verification": "passed",
"createdAt": "2026-07-12T10:00:00.000Z",
"completedAt": "2026-07-12T10:00:30.000Z",
"error": null
}Statuses: pending → assigned → rendering → complete | failed | canceled
POST /api/v1/renders/:id/cancel
Cancel a render. Required scope: render:cancel. Credits are not charged for canceled renders.
POST /api/v1/bundles
Request a short-lived R2 upload URL. Required scope: bundle:write. Send {sha256, remotionVersion, sizeBytes}, PUT the tar.gz bytes to uploadUrl, then call POST /api/v1/bundles/:sha256/complete. Completion downloads the object, verifies its SHA-256 and size, and registers it only for the calling workspace.
If the farm has no active runner for the requested Remotion version, the API returns UNSUPPORTED_REMOTION_VERSION and the current supportedRemotionVersions.
GET /api/v1/versions
Preflight the active farm-managed runner matrix. Required scope: bundle:write. Returns {supportedRemotionVersions: [{remotionVersion, payloadVersion}]}. Bundle registration and enqueue return 422 UNSUPPORTED_REMOTION_VERSION with the supported version names when no matching runner exists.
Farm operators add support by creating a versioned runner app, adding it to scripts/publish-runner-payload.ts, and running bun scripts/publish-runner-payload.ts --version=<version>. Tenants never publish runner binaries.
GET /api/v1/balance
Required scope: balance:read.
{"balance": 100, "holds": 5, "available": 95}/api/v1/webhooks
GET requires webhook:read. POST, PATCH /:id, and DELETE /:id require webhook:write. Every operation is scoped to the API key's workspace. The signing secret is returned once on creation.
Webhooks
Terminal status deliveries are sent to your configured URL:
POST <your-webhook-url>
X-Decent-Signature: <HMAC-SHA256>
X-Decent-Timestamp: <unix-seconds>
{
"event": "render.complete",
"renderId": "job-render-...",
"status": "complete",
"outputUrl": "https://...",
"creditsReserved": 5,
"creditsSettled": 5,
"verification": "pending"
}Completed output is delivered immediately with verification pending. The referee later emits render.verification with passed or flagged. Flagged renders retain their outputUrl; only operator payout is voided. The signature is hex HMAC-SHA256 over <timestamp>.<raw-body>.