API reference
Base URL: https://pixbix.app/api — every endpoint below is relative to it. All requests and responses are JSON unless stated otherwise.
All endpoints#
Every endpoint in the public API, grouped by what it renders. Image, video and screenshot endpoints are documented on their own pages — the links below land on the exact one.
Conventions#
Authentication
Send your key as x-api-key, or as Authorization: Bearer <key>. Both are equivalent.
x-api-key: pk_live_1a2b3c4d…
Content-Type: application/json| Prefix | Behaviour |
|---|---|
pk_live_ | Consumes credits. Watermark follows your plan. |
pk_test_ | Never consumes credits. Always watermarked. Lower rate limit. |
Response envelope
Every JSON response uses the same shape, so error handling can be written once.
{
"success": true,
"message": "Render queued",
"data": { "id": "rnd_8f2a1c", "status": "queued" },
"pagination": { "page": 1, "limit": 20, "total": 84, "totalPages": 5 }
}Branch on code, never on message — messages are written for humans and will change.
Idempotency
Send an Idempotency-Key header on any render request. A retry with the same key returns the original render instead of creating and billing a second one. Keys are scoped to your workspace and never expire.
Rate limits
Limits are per workspace, per minute, and set by your plan — 20/min on Free up to 1,200/min on Scale. Exceeding one returns 429 with code RATE_LIMIT_EXCEEDED. Concurrency is not a rate limit and never returns an error — renders past your plan’s concurrent allowance are queued and start automatically. See LIMIT_QUEUE_DEPTH below for the one ceiling that does refuse.
Pagination, sorting and filtering
Every list endpoint accepts the same four parameters: page (default 1), limit (default 20, max 100), sort and order (asc or desc). Most also accept search, plus filters of their own — each endpoint below lists the columns it can sort by and the filters it takes.
curl "https://pixbix.app/api/v1/render?status=failed&sort=createdAt&order=desc&page=2&limit=50" \
-H "x-api-key: $PIXBIX_API_KEY"Filters that name a set — status, kind, type — accept several values comma-separated and match any of them. Date filters come in pairs, such as createdFrom and createdTo, and take an ISO date.
Sorting is restricted to the columns each endpoint names, so that every ordering the API offers is one the database can serve from an index. An unknown column returns 422 with code INVALID_LIST_QUERY and a message naming the ones that are allowed — as does a filter value outside its set. Results are always tiebroken by id, so a row cannot appear on two pages of the same walk.
Paging very deep is refused rather than served slowly: past an offset of 100,000 the same 422 asks you to narrow the query with a filter or a date range instead.
Errors#
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Malformed body, or neither templateId nor edit supplied |
| 401 | NO_API_KEY | No key sent |
| 401 | INVALID_API_KEY | Key unknown, revoked, inactive or expired |
| 403 | INSUFFICIENT_SCOPE | The key lacks the scope this endpoint requires |
| 403 | IP_NOT_ALLOWED | Caller IP is not on the key’s allowlist |
| 403 | ORG_SUSPENDED | Workspace suspended — contact support |
| 402 | INSUFFICIENT_CREDITS | Not enough credits for this render |
| 402 | LIMIT_QUEUE_DEPTH | This workspace already has the most renders your plan will hold queued at once |
| 402 | LIMIT_VIDEO_DURATION | Edit is longer than your plan allows |
| 402 | LIMIT_VIDEO_RESOLUTION | Requested resolution exceeds your plan |
| 402 | LIMIT_VIDEO_FPS | Requested frame rate exceeds your plan |
| 402 | LIMIT_IMAGE_SIZE | Requested image dimension exceeds your plan |
| 402 | FEATURE_VIDEOENABLED | Video rendering is not included in your plan |
| 402 | FEATURE_WORKFLOWSENABLED | Workflow automation is not included in your plan |
| 402 | LIMIT_WORKFLOWRUNS | Monthly workflow run allowance used up |
| 402 | LIMIT_WORKFLOWMAXSTEPS | Workflow has more steps than your plan allows |
| 402 | LIMIT_WEBHOOKDELIVERIES | Monthly webhook delivery allowance used up |
| 402 | LIMIT_APIREQUESTS | Monthly API request allowance used up |
| 404 | TEMPLATE_NOT_FOUND | Template does not exist or is not available to you |
| 403 | TEMPLATE_NOT_OWNED | The template belongs to another workspace — copy it into yours and render the copy |
| 409 | TEMPLATE_NOT_PUBLISHED | The template is a draft, or archived. Publish it before rendering from it |
| 409 | TEMPLATE_STALE | Someone else saved this template since you loaded it — reload before saving |
| 422 | INVALID_CATEGORY | The main category is missing, or the subcategory does not belong to it |
| 422 | NOT_PUBLISHABLE | The template is not ready to publish; see the checks in the response |
| 409 | ALREADY_SETTLED | Render already finished — cannot be cancelled |
| 422 | TEMPLATE_VALIDATION_FAILED | Field values failed validation; see the errors object |
| 422 | EMPTY_TIMELINE | The timeline has no duration |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests this minute |
| 503 | ENGINE_NOT_CONFIGURED | Video rendering unavailable on this deployment |
402 is not a failure to retry
A402 means a business rule stopped the request — no credits, or a plan ceiling. Retrying will fail identically until the customer upgrades or buys credits. Surface it to a human rather than putting it in a retry loop.Renders#
Create a render
/v1/renderAPI keyrenders:writestatus: "done" and a URL. Video is queued and returns 202 with status: "queued" — poll the render, or wait for a webhook.Parameters
templateIdstringoptional- The template to render. Required unless you supply an `edit` instead.
valuesobjectoptional- Field values keyed by field key. Validated against the template schema. Also accepted as `fields`, or as `merge` find/replace pairs.
editobjectoptional- A complete edit spec (timeline + output), for rendering without a saved template. See the video guide.
outputobjectoptional- Overrides the template’s output settings — format, resolution, size, fps, quality, codec, range, poster, thumbnail.
callbackstring (URL)optional- Notified when the render settles. Overrides the workspace default.
idempotencyKeystringoptional- Alternative to the Idempotency-Key header.
Query parameters
formatstringoptional- Set to
binaryto receive raw image bytes instead of JSON. Still images only. typestringoptional- Shorthand output format: png, jpeg, pdf, mp4, gif.
scaleintegeroptional- Device scale factor for stills, 1–3.Default:
1 resolutionstringoptional- preview, mobile, sd, hd, fhd or 4k.
fpsintegeroptional- Frame rate for video output.
curl -X POST https://pixbix.app/api/v1/render \
-H "x-api-key: pk_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4471-card" \
-d '{
"templateId": "sale-card-square",
"values": {
"product": "https://cdn.shop.com/sku-4471.jpg",
"title": "Cotton Kurta Set",
"price": "₹1,249",
"badge": "50% OFF"
},
"output": { "format": "png", "scale": 2 }
}'Retrieve a render
/v1/render/{id}API keyrenders:read| status | Meaning |
|---|---|
queued | Accepted, waiting for a worker |
fetching | Downloading and probing assets |
rendering | Compositing and encoding |
saving | Generating poster/thumbnail and uploading |
done | Finished — `url` is populated |
failed | Failed — `error` explains why; credits were refunded |
cancelled | Cancelled by you; credits were refunded |
List renders
/v1/renderAPI keyrenders:readQuery parameters
statusstringoptional- Filter by render status.
kindstringoptional- image or video.
templateIdstringoptional- Only renders from this template.
pageintegeroptional- Page number.Default:
1 limitintegeroptional- Items per page, max 100.Default:
20
Cancel a render
/v1/render/{id}/cancelAPI keyrenders:write409 if it has already settled. A render already being encoded stops at the next stage boundary rather than instantly.Estimate cost
/v1/render/estimateAPI keyrenders:read{
"success": true,
"data": {
"kind": "video",
"credits": 15,
"durationSec": 15,
"size": { "width": 1080, "height": 1920 },
"breakdown": {
"duration": "15.00s",
"size": "1080×1920",
"fps": 30,
"format": "mp4",
"codec": "h264"
}
}
}Templates#
List templates
/v1/templatesAPI keytemplates:readQuery parameters
scopestringoptionalminefor your own,libraryfor public only. Omit for both.statusstringoptionaldraft,publishedorarchived. Applies to your own templates only.kindstringoptional- image or video.
categoryIdstringoptional- Filter by category.
searchstringoptional- Match name, tags and description.
sortstringoptional- popular, newest, oldest, updated or name.Default:
popular
Notable response fields
canRenderbooleanoptional- A render naming this template would be accepted. False for every library template you have not copied.
isOwnbooleanoptional- Owned by your workspace.
inLibrarybooleanoptional- Listed in the shared library, so anyone may copy it.
statusstringoptional- draft, published or archived.
visibilitystringoptional- private or public.
Copy a template into your workspace
/v1/templates/{id}/duplicateAPI keytemplates:writeThe copy arrives as a private draftwith its usage, version and review history cleared. Publish it before rendering. It counts against your plan’s template allowance like any other template you own.
{
"success": true,
"message": "Added to your templates. Publish it when you are ready to generate from it.",
"data": {
"id": "tpl_9c41b2",
"name": "Diwali sale story",
"status": "draft",
"visibility": "private",
"version": 1
}
}Retrieve a template schema
/v1/templates/{id}API keytemplates:read{
"success": true,
"data": {
"id": "sale-card-square",
"name": "Sale card — square",
"kind": "image",
"width": 1080,
"height": 1080,
"aspectRatio": "1:1",
"version": 4,
"fieldGroups": ["Content", "Branding"],
"fields": [
{
"key": "title",
"label": "Product name",
"type": "text",
"group": "Content",
"required": true,
"defaultValue": null,
"placeholder": "Cotton Kurta Set",
"config": { "maxLength": 48 }
},
{
"key": "product",
"label": "Product photo",
"type": "image",
"group": "Content",
"required": true,
"config": { "aspectRatio": "1:1" }
},
{
"key": "badge",
"label": "Offer badge",
"type": "text",
"group": "Content",
"required": false,
"config": { "maxLength": 12 }
}
]
}
}Assets#
The media a template draws from. Rendered from the same catalogue as the image and video references, so the parameters here are the ones the runner sends.
List caption providers
/api/v1/captions/providersAPI keyintegrations:read{
"success": true,
"message": "2 caption providers connected",
"data": {
"providers": [
{
"slug": "deepgram",
"name": "Deepgram",
"connected": true,
"account": "Acme Media",
"recommended": true,
"support": {
"video": true,
"autoLanguage": true,
"multiLanguage": true,
"diarize": true,
"keywords": true,
"profanityFilter": true,
"maxBytes": 524288000
}
},
{
"slug": "aws-transcribe",
"name": "Amazon Transcribe",
"connected": true,
"account": "acme-transcribe · ap-south-1",
"recommended": false
},
{
"slug": "google-speech",
"name": "Google Speech-to-Text",
"connected": false,
"account": null,
"recommended": false
}
],
"connected": 2,
"cache": {
"transcribed": 41,
"reused": 386,
"secondsSaved": 9142,
"hitRate": 0.904
}
}
}Try it
/api/v1/captions/providersShow as cURL
curl -X GET "https://pixbix.app/api/v1/captions/providers" \ -H "x-api-key: pk_live_your_key"
Get the default provider’s options
/api/v1/captions/optionsAPI keyintegrations:read{
"success": true,
"data": {
"provider": "deepgram",
"name": "Deepgram",
"support": {
"video": true,
"autoLanguage": true,
"multiLanguage": true,
"diarize": true,
"keywords": true,
"profanityFilter": true,
"maxBytes": 524288000
},
"languages": [
{
"code": "auto",
"label": "Detect automatically"
},
{
"code": "en-IN",
"label": "English (India)"
}
],
"models": [
{
"id": "nova-3",
"label": "Nova 3",
"hint": "The default. Best accuracy, real-world audio, and the fastest of the three."
}
]
}
}Try it
/api/v1/captions/optionsShow as cURL
curl -X GET "https://pixbix.app/api/v1/captions/options" \ -H "x-api-key: pk_live_your_key"
Get a provider’s options
/api/v1/captions/options/:providerAPI keyintegrations:readPath parameters
providerstringoptional- One of `deepgram`, `aws-transcribe`, `google-speech`. Omit the segment entirely for the provider that would be used by default.
{
"success": true,
"data": {
"provider": "deepgram",
"name": "Deepgram",
"support": {
"video": true,
"autoLanguage": true,
"multiLanguage": true,
"diarize": true,
"keywords": true,
"profanityFilter": true,
"maxBytes": 524288000
},
"languages": [
{
"code": "auto",
"label": "Detect automatically"
},
{
"code": "en-IN",
"label": "English (India)"
}
],
"models": [
{
"id": "nova-3",
"label": "Nova 3",
"hint": "The default. Best accuracy, real-world audio, and the fastest of the three."
}
]
}
}Try it
/api/v1/captions/options/deepgramShow as cURL
curl -X GET "https://pixbix.app/api/v1/captions/options/deepgram" \ -H "x-api-key: pk_live_your_key"
Generate captions
/api/v1/captionsAPI keyassets:writeCost No render credits. The provider bills your own account per audio-minute — and not at all on a cache hit.
Body parameters
audioUrlstringoptional- URL of the recording. Audio or video. One of this, `assetId` or `renderId` is required.
assetIdstringoptional- An audio or video asset in your library, instead of a URL. The fastest route to a cache hit — the library already knows the file’s checksum, so a repeat needs no download at all.
renderIdstringoptional- A finished render, instead of a URL — transcribes its audio track.
providerstringoptional- Which speech provider. Omit it and the best connected one is chosen — Deepgram, then Amazon, then Google. Naming a provider that cannot read your file returns 422 saying which ones can.
languageCodestringoptional- BCP-47 tag, or `auto` to detect. Codes differ per provider — see `/v1/captions/options`.
alternativeLanguageCodesstring[]optional- Other languages the speaker may switch to mid-recording.
modelstringoptional- Provider model id. Omit it for the provider’s own default.
diarizebooleanoptional- Label who is speaking. Deepgram and Amazon only.
keywordsstring[]optional- Names, jargon and product words to bias the model towards. Deepgram only.
wordsPerCuenumberoptional- Words per caption. Changing this on a repeat is free — the cache re-cuts the stored word timings rather than transcribing again.
charsPerCuenumberoptional- Characters per caption. The limit that actually governs on a phone. Defaults to 42.
maxCueSecnumberoptional- Never hold one caption longer than this. Defaults to 6.
punctuationbooleanoptional- Ask the recogniser to punctuate. Defaults to on — captions without it read badly, and sentence ends are what cues are broken on.
filterProfanitybooleanoptional- Mask profanity in the transcript. Deepgram and Google only.
cachebooleanoptional- Set false (or `"fresh"`) to force a new transcription. On by default: an identical recording with identical settings is answered from an earlier transcription for nothing.
savebooleanoptional- Set false to skip writing .vtt and .srt files to storage.
{
"assetId": "ast_7f21",
"provider": "deepgram",
"languageCode": "en-IN",
"wordsPerCue": 5,
"diarize": false
}Try it
/api/v1/captionsShow as cURL
curl -X POST "https://pixbix.app/api/v1/captions" \
-H "x-api-key: pk_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "assetId": "ast_7f21", "provider": "deepgram", "languageCode": "en-IN", "wordsPerCue": 5, "diarize": false }'Generate captions (older path)
/api/v1/transcriptionsAPI keyassets:writeCost No render credits. The provider bills your own account per audio-minute — and not at all on a cache hit.
Body parameters
audioUrlstringoptional- URL of the recording. Audio or video. One of this, `assetId` or `renderId` is required.
assetIdstringoptional- An audio or video asset in your library, instead of a URL.
renderIdstringoptional- A finished render, instead of a URL.
providerstringoptional- Which speech provider. Omit it and the best connected one is chosen.
languageCodestringoptional- BCP-47 tag, or `auto` to detect.
wordsPerCuenumberoptional- Words per caption.
cachebooleanoptional- Set false to force a new transcription.
savebooleanoptional- Set false to skip writing .vtt and .srt files to storage.
{
"audioUrl": "https://cdn.acme.com/voice.mp3",
"languageCode": "en-IN",
"wordsPerCue": 7
}Try it
/api/v1/transcriptionsShow as cURL
curl -X POST "https://pixbix.app/api/v1/transcriptions" \
-H "x-api-key: pk_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "audioUrl": "https://cdn.acme.com/voice.mp3", "languageCode": "en-IN", "wordsPerCue": 7 }'List transcriptions
/api/v1/transcriptionsAPI keyassets:readQuery parameters
limitnumberoptional- Rows to return, 1–100. Defaults to 20.
{
"success": true,
"data": [
{
"id": "trs_31c8",
"status": "done",
"languageCode": "en-IN",
"srtUrl": "https://cdn.pixbix.app/media/org_4c1d/caption/trs_31c8.srt"
}
]
}Try it
/api/v1/transcriptions?limit=20Show as cURL
curl -X GET "https://pixbix.app/api/v1/transcriptions?limit=20" \ -H "x-api-key: pk_live_your_key"
Get a transcription
/api/v1/transcriptions/:idAPI keyassets:readPath parameters
idstringrequired- Transcription id.
{
"success": true,
"data": {
"id": "trs_31c8",
"status": "done",
"text": "Diwali offers are live now.",
"cues": [
{
"start": 0,
"end": 2.4,
"text": "Diwali offers are live now."
}
],
"vttUrl": "https://cdn.pixbix.app/media/org_4c1d/caption/trs_31c8.vtt",
"srtUrl": "https://cdn.pixbix.app/media/org_4c1d/caption/trs_31c8.srt"
}
}Try it
/api/v1/transcriptions/trs_31c8Show as cURL
curl -X GET "https://pixbix.app/api/v1/transcriptions/trs_31c8" \ -H "x-api-key: pk_live_your_key"
List assets
/api/v1/assetsAPI keyassets:readQuery parameters
pagenumberoptional- Page number, from 1.
limitnumberoptional- Rows per page, 1–100. Defaults to 24.
sortstringoptional- Column to order by: createdAt, name, sizeBytes, type, durationSec. Defaults to `createdAt`.
order"asc" | "desc"optional- Sort direction. Defaults to `desc` for dates and counts.
searchstringoptional- Case-insensitive match across name, description, tags. Up to 128 characters.
scopestringoptional- `workspace` (default) for your own uploads, `global` for the pixbix stock library, `all` for both. The stock library is read-only.
typestringoptional- Filter by media type: `image`, `video`, `audio`, `font`, `lottie` or `svg`. Comma-separate several to match any of them.
statusstringoptional- `ready`, `processing`, `uploading` or `failed`. Only `ready` assets can be rendered with.
folderstringoptional- Only assets filed in this collection.
tagsstringoptional- One or more tags, comma-separated.
{
"success": true,
"data": [
{
"id": "ast_19fa",
"type": "image",
"scope": "workspace",
"name": "lamp.jpg",
"description": null,
"url": "https://cdn.pixbix.app/assets/ast_19fa.jpg",
"mimeType": "image/jpeg",
"sizeBytes": 184320,
"width": 1200,
"height": 1200,
"durationSec": null,
"tags": [
"product",
"lighting"
]
}
]
}Try it
/api/v1/assets?page=1&limit=24&sort=createdAt&order=desc&search=diwali&scope=workspace&type=image&status=ready&folder=Backgrounds&tags=harbour%2CduskShow as cURL
curl -X GET "https://pixbix.app/api/v1/assets?page=1&limit=24&sort=createdAt&order=desc&search=diwali&scope=workspace&type=image&status=ready&folder=Backgrounds&tags=harbour%2Cdusk" \ -H "x-api-key: pk_live_your_key"
Upload an asset
/api/v1/assetsAPI keyassets:writeCost Counts against your plan’s storage, not against credits.
Body parameters
filefilerequired- The asset itself. Max 200 MB by default.
tagsstringoptional- Comma-separated keywords, up to 20. Searchable.
descriptionstringoptional- Free text, up to 2000 characters. Searchable.
folderstringoptional- Collection to file the asset under.
{
"success": true,
"data": {
"id": "ast_19fa",
"url": "https://cdn.pixbix.app/media/org_4c1d/image/ast_19fa.jpg"
}
}This endpoint takes multipart/form-data, which the JSON runner below cannot construct.
Delete an asset
/api/v1/assets/:idAPI keyassets:writePath parameters
idstringrequired- Asset id.
{
"success": true,
"message": "Asset deleted"
}Deleting is destructive — run it against an asset id you own from your own client.
Integrations#
Read and write the third-party accounts a workspace has connected. Connecting an account happens once, in the dashboard under Integrations — OAuth needs a person at a consent screen, so there is no API endpoint for it. Everything below drives a connection somebody has already made.
402 with LIMIT_INTEGRATION_NOT_ALLOWED.Two failures are worth handling separately. INTEGRATION_NOT_CONNECTED means nobody has connected that provider yet. INTEGRATION_REAUTH_REQUIRED means somebody did, and the grant has since lapsed — a customer revoked access at Google, or changed their password. Only the second one means a job that used to work has just stopped, and it is the one worth alerting on.
Sheets and Drive are one integration — google-workspace — behind a single Google connection, so a workspace that has connected Google can call both. The paths are namespaced by product under the connection that owns the grant.
| Product | Path prefix | What it does |
|---|---|---|
| Sheets | /v1/integrations/google-workspace/sheets | Read rows to drive a batch of renders, and write the finished URLs back beside them. |
| Drive | /v1/integrations/google-workspace/drive | Import source assets into the media library, and deliver finished renders into a folder. |
| ElevenLabs | /v1/integrations/elevenlabs | Generate a voice-over from a script, saved to your media library as an MP3. |
| MotherBot | /v1/integrations/motherbot | Deliver a finished render to WhatsApp — one personalised video per contact, or one broadcast to many. |
| Google Speech-to-Text | /v1/integrations/google-speech | Transcribe a voice-over into word-timed captions, as engine cues and as WebVTT and SRT files. |
script and the engine times the words against the voice — see the video guide.cuesis shaped exactly like the engine’s caption asset, carrying per-word timings, so it drops onto a timeline and drives the karaoke highlight to the syllable. The .vtt and .srtfiles are what a player’s subtitle track and a social upload take. Google bills your own Cloud project per audio-minute; pixbix charges no render credits. A finished video cannot be transcribed directly — caption the voice-over that went into it.VIDEO can carry a video: list your templates first and read headerFormat.List connected accounts
/api/v1/integrationsAPI keyintegrations:read{
"success": true,
"data": [
{
"id": "int_7f21",
"provider": "google-workspace",
"status": "connected",
"account": {
"email": "ops@acme.in",
"name": "Acme Ops"
},
"connectedAt": "2026-08-01T09:12:44.000Z"
}
]
}Try it
/api/v1/integrationsShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations" \ -H "x-api-key: pk_live_your_key"
List spreadsheets
/api/v1/integrations/google-workspace/sheets/spreadsheetsAPI keyintegrations:readQuery parameters
searchstringoptional- Filter by name, substring match.
limitnumberoptional- 1–100. Defaults to 25.
pageTokenstringoptional- Cursor from a previous response’s `nextPageToken`.
{
"success": true,
"data": {
"files": [
{
"id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
"name": "Product catalogue",
"url": "https://docs.google.com/spreadsheets/d/1BxiMVs0.../edit",
"modifiedAt": "2026-08-12T04:31:00.000Z"
}
],
"nextPageToken": null
}
}Try it
/api/v1/integrations/google-workspace/sheets/spreadsheets?search=products&limit=25Show as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/sheets/spreadsheets?search=products&limit=25" \ -H "x-api-key: pk_live_your_key"
Get spreadsheet tabs
/api/v1/integrations/google-workspace/sheets/spreadsheets/:spreadsheetIdAPI keyintegrations:readPath parameters
spreadsheetIdstringrequired- Spreadsheet id, the long string in its Google URL.
{
"success": true,
"data": {
"id": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
"name": "Product catalogue",
"sheets": [
{
"id": 0,
"title": "Products",
"index": 0,
"rowCount": 1000,
"columnCount": 12
}
]
}
}Try it
/api/v1/integrations/google-workspace/sheets/spreadsheets/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upmsShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/sheets/spreadsheets/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms" \ -H "x-api-key: pk_live_your_key"
Read rows
/api/v1/integrations/google-workspace/sheets/spreadsheets/:spreadsheetId/valuesAPI keyintegrations:readPath parameters
spreadsheetIdstringrequired- Spreadsheet id.
Query parameters
rangestringoptional- A1 notation. A bare tab name reads that whole tab. Defaults to `Sheet1`.
as"records" | "values"optional- `records` keys each row by the header row; `values` returns the raw grid.
renderOption"FORMATTED_VALUE" | "UNFORMATTED_VALUE" | "FORMULA"optional- How cells are rendered. Defaults to the formatted value, as displayed in the sheet.
{
"success": true,
"data": {
"range": "Products!A1:F51",
"headers": [
"sku",
"name",
"price",
"image"
],
"records": [
{
"sku": "AC-100",
"name": "Copper bottle",
"price": "₹899",
"image": "https://cdn.acme.in/ac-100.jpg"
}
]
}
}Try it
/api/v1/integrations/google-workspace/sheets/spreadsheets/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/values?range=Products%21A1%3AF&as=records&renderOption=FORMATTED_VALUEShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/sheets/spreadsheets/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/values?range=Products%21A1%3AF&as=records&renderOption=FORMATTED_VALUE" \ -H "x-api-key: pk_live_your_key"
Write rows
/api/v1/integrations/google-workspace/sheets/spreadsheets/:spreadsheetId/valuesAPI keyintegrations:writePath parameters
spreadsheetIdstringrequired- Spreadsheet id.
Body parameters
rangestringrequired- A1 notation, e.g. `Products!A1`.
valuesarray[array]required- Rows, each an array of cell values.
mode"append" | "overwrite"optional- Defaults to `append`, which inserts new rows rather than writing over what follows the range.
rawbooleanoptional- Store values verbatim instead of interpreting them as a person typing would — set it for codes that look like dates.
{
"range": "Renders!A1",
"values": [
[
"AC-100",
"https://cdn.pixbix.app/renders/ac-100.png",
"2026-08-15"
],
[
"AC-101",
"https://cdn.pixbix.app/renders/ac-101.png",
"2026-08-15"
]
],
"mode": "append"
}This writes to a real spreadsheet in your Google account. Run it from your own client, against a sheet you are happy to change.
Create a spreadsheet
/api/v1/integrations/google-workspace/sheets/spreadsheetsAPI keyintegrations:writeBody parameters
titlestringrequired- Name of the new spreadsheet.
sheetTitlestringoptional- Name of its first tab. Defaults to `Sheet1`.
headersarray[string]optional- Written into the first row.
{
"title": "August campaign renders",
"sheetTitle": "Renders",
"headers": [
"sku",
"render url",
"created"
]
}This creates a real file in your Google account.
List Drive files
/api/v1/integrations/google-workspace/drive/filesAPI keyintegrations:readQuery parameters
folderIdstringoptional- List inside one folder. Omit for the top level.
searchstringoptional- Filter by name, substring match.
kindstringoptional- `image`, `video`, `audio`, `font`, `folder`, or a full MIME type.
limitnumberoptional- 1–200. Defaults to 50.
pageTokenstringoptional- Cursor from a previous response’s `nextPageToken`.
{
"success": true,
"data": {
"files": [
{
"id": "1a2B3c4D5e6F",
"name": "brand-logo.png",
"mimeType": "image/png",
"sizeBytes": 48211,
"isFolder": false,
"webViewUrl": "https://drive.google.com/file/d/1a2B3c4D5e6F/view"
}
],
"nextPageToken": null
}
}Try it
/api/v1/integrations/google-workspace/drive/files?search=logo&kind=image&limit=50Show as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/drive/files?search=logo&kind=image&limit=50" \ -H "x-api-key: pk_live_your_key"
Upload to Drive
/api/v1/integrations/google-workspace/drive/filesAPI keyintegrations:writeBody parameters
urlstringrequired- Public http(s) URL to upload.
namestringoptional- Filename in Drive. Defaults to the last path segment of the URL.
folderIdstringoptional- Destination folder. Omit for the account’s root.
mimeTypestringoptional- Overrides the content type reported by the source URL.
{
"url": "https://cdn.pixbix.app/renders/ac-100.png",
"name": "AC-100 poster.png",
"folderId": "1QfolderIdFromDrive"
}This writes a real file into your Google Drive.
Create a Drive folder
/api/v1/integrations/google-workspace/drive/foldersAPI keyintegrations:writeBody parameters
namestringrequired- Folder name.
parentIdstringoptional- Parent folder. Omit for the account’s root.
{
"name": "August campaign"
}This creates a real folder in your Google Drive.
Read Google Contacts
/api/v1/integrations/google-workspace/contactsAPI keyintegrations:readQuery parameters
searchstringoptional- Match against name, email or phone. Omit to page through everyone.
limitnumberoptional- Contacts per page, up to 1000.
pageTokenstringoptional- From the previous response, to fetch the next page.
{
"success": true,
"message": "Contacts",
"data": {
"contacts": [
{
"id": "people/c1234567890",
"displayName": "Priya Sharma",
"firstName": "Priya",
"lastName": "Sharma",
"email": "priya@acme.in",
"allEmails": "priya@acme.in, priya.sharma@gmail.com",
"phone": "+91 98765 43210",
"allPhones": "+91 98765 43210",
"organization": "Acme Retail",
"jobTitle": "Head of Marketing",
"city": "Mumbai",
"country": "India",
"photoUrl": "https://lh3.googleusercontent.com/…",
"notes": "",
"groupIds": [
"contactGroups/myContacts"
]
}
],
"nextPageToken": "CJHm2wIQAQ",
"total": 412
}
}Try it
/api/v1/integrations/google-workspace/contacts?search=priya&limit=50Show as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/contacts?search=priya&limit=50" \ -H "x-api-key: pk_live_your_key"
List contact labels
/api/v1/integrations/google-workspace/contacts/groupsAPI keyintegrations:read{
"success": true,
"message": "3 label(s)",
"data": [
{
"id": "contactGroups/myContacts",
"name": "My Contacts",
"count": 412
},
{
"id": "contactGroups/7a3f1c2e",
"name": "Clients",
"count": 86
},
{
"id": "contactGroups/starred",
"name": "Starred",
"count": 12
}
]
}Try it
/api/v1/integrations/google-workspace/contacts/groupsShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-workspace/contacts/groups" \ -H "x-api-key: pk_live_your_key"
Import a Drive file
/api/v1/integrations/google-workspace/drive/files/:fileId/importAPI keyassets:writePath parameters
fileIdstringrequired- Drive file id.
Body parameters
folderstringoptional- Media-library folder to file it under.
tagsstringoptional- Comma-separated tags.
{
"folder": "brand",
"tags": "logo,brand"
}Importing consumes your storage allowance — run it from your own client.
List voices
/api/v1/integrations/elevenlabs/voicesAPI keyintegrations:read{
"success": true,
"data": [
{
"id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"category": "premade",
"previewUrl": "https://storage.googleapis.com/eleven-public-prod/…/sample.mp3",
"labels": {
"accent": "american",
"gender": "female"
}
}
]
}Try it
/api/v1/integrations/elevenlabs/voicesShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/elevenlabs/voices" \ -H "x-api-key: pk_live_your_key"
List speech models
/api/v1/integrations/elevenlabs/modelsAPI keyintegrations:read{
"success": true,
"data": [
{
"id": "eleven_multilingual_v2",
"name": "Eleven Multilingual v2",
"languages": [
{
"id": "en",
"name": "English"
},
{
"id": "hi",
"name": "Hindi"
}
],
"maxCharacters": 5000
}
]
}Try it
/api/v1/integrations/elevenlabs/modelsShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/elevenlabs/models" \ -H "x-api-key: pk_live_your_key"
Check character allowance
/api/v1/integrations/elevenlabs/usageAPI keyintegrations:read{
"success": true,
"data": {
"tier": "creator",
"characterCount": 41200,
"characterLimit": 100000,
"charactersRemaining": 58800,
"resetsAt": "2026-09-01T00:00:00.000Z"
}
}Try it
/api/v1/integrations/elevenlabs/usageShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/elevenlabs/usage" \ -H "x-api-key: pk_live_your_key"
Generate a voice-over
/api/v1/integrations/elevenlabs/speechAPI keyassets:writeCost No pixbix credits. Consumes characters from your own ElevenLabs plan, and storage from your pixbix quota.
Body parameters
textstringrequired- The script to speak. Up to 5,000 characters per request.
voiceIdstringrequired- From the voices endpoint.
modelIdstringoptional- Defaults to eleven_multilingual_v2.
stabilitynumberoptional- 0–1. Low is expressive and varies between takes; high is consistent and flatter.
similarityBoostnumberoptional- 0–1. How closely the output holds to the original voice.
stylenumberoptional- 0–1. Delivery emphasis. Adds latency above 0.
namestringoptional- Filename in the media library. Defaults to the opening words of the script.
folderstringoptional- Media-library folder to file it under.
{
"text": "Diwali sale — fifty percent off, this week only.",
"voiceId": "21m00Tcm4TlvDq8ikWAM",
"modelId": "eleven_multilingual_v2",
"name": "diwali-vo.mp3",
"folder": "voice-overs"
}Generating speech spends characters from your ElevenLabs plan and storage from your quota, so it is not fired from the docs.
List caption languages
/api/v1/integrations/google-speech/languagesAPI keyintegrations:read{
"success": true,
"data": [
{
"code": "en-IN",
"label": "English (India)"
},
{
"code": "hi-IN",
"label": "Hindi"
}
]
}Try it
/api/v1/integrations/google-speech/languagesShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/google-speech/languages" \ -H "x-api-key: pk_live_your_key"
Generate captions
/api/v1/integrations/google-speech/captionsAPI keyassets:writeCost No pixbix credits. Google bills your own Cloud project per audio-minute, and the two subtitle files count against your storage quota.
Body parameters
audioUrlstringoptional- A public MP3, WAV, FLAC or OGG. A video file is refused — transcribe the voice-over that went into it.
assetIdstringoptional- An audio asset in your media library, instead of a URL.
renderIdstringoptional- A finished audio render, instead of a URL.
languageCodestringoptional- BCP-47. Defaults to en-US. Getting this wrong returns confident nonsense rather than an error.
alternativeLanguageCodesarrayoptional- Up to three more languages Google may pick from — worth setting for audio that switches mid-sentence.
wordsPerCuenumberoptional- 1–12, default 4. Captions also break at a full stop and at any pause over a second.
punctuationbooleanoptional- Infer full stops and commas. On by default; captions read badly without them.
filterProfanitybooleanoptional- Mask strong language. Off by default — Google’s filter is heavy-handed.
savebooleanoptional- Write the .vtt and .srt to your media library. On by default; pass false for the cues alone.
namestringoptional- Base filename for the saved files. Defaults to the audio’s own name.
{
"assetId": "ast_4b7c",
"languageCode": "en-IN",
"wordsPerCue": 4
}Transcription is billed by audio-minute to your own Google Cloud project and writes two files to your library, so it is not fired from the docs.
List messaging channels
/api/v1/integrations/motherbot/channelsAPI keyintegrations:readQuery parameters
channelstringoptional- Restrict to one channel: whatsapp, sms, rcs, email, telegram, line, viber, messenger, instagram or webchat.
statusstringoptional- Defaults to connected.
{
"success": true,
"data": [
{
"id": "66f1c2a0d3b4e5f6a7b8c9d0",
"channel": "whatsapp",
"provider": "meta",
"label": "Acme Retail",
"identifier": "919876543210",
"isDefault": true,
"status": "connected",
"capabilities": {
"template": true,
"text": true,
"media": [
"image",
"video",
"document",
"audio"
],
"interactive": [
"button",
"list",
"cta_url"
]
}
}
]
}Try it
/api/v1/integrations/motherbot/channels?channel=whatsapp&status=connectedShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/motherbot/channels?channel=whatsapp&status=connected" \ -H "x-api-key: pk_live_your_key"
List WhatsApp templates
/api/v1/integrations/motherbot/templatesAPI keyintegrations:readQuery parameters
statusstringoptional- APPROVED (default), PENDING, REJECTED, DISABLED or DRAFT.
categorystringoptional- MARKETING, UTILITY or AUTHENTICATION.
languagestringoptional- Language code, e.g. en_US or hi.
searchstringoptional- Partial name match.
accountIdstringoptional- Only templates approved on this WhatsApp number. Templates are approved per number, so a send from one number cannot use another’s.
limitnumberoptional- Up to 100 per page.
{
"success": true,
"data": [
{
"id": "66f1c2a0d3b4e5f6a7b8c9d0",
"accountId": "66f1c2a0d3b4e5f6a7b8c9d0",
"name": "order_ready_video",
"category": "MARKETING",
"language": "en",
"status": "APPROVED",
"headerFormat": "VIDEO",
"bodyVariableCount": 2,
"variables": [
"name",
"order_id"
],
"usageCount": 1284
}
]
}Try it
/api/v1/integrations/motherbot/templates?status=APPROVED&category=MARKETING&language=en&search=order&accountId=66f1c2a0d3b4e5f6a7b8c9d0&limit=100Show as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/motherbot/templates?status=APPROVED&category=MARKETING&language=en&search=order&accountId=66f1c2a0d3b4e5f6a7b8c9d0&limit=100" \ -H "x-api-key: pk_live_your_key"
List WhatsApp contacts
/api/v1/integrations/motherbot/contactsAPI keyintegrations:readQuery parameters
tagstringoptional- Only contacts carrying this tag.
searchstringoptional- Partial name or number match.
limitnumberoptional- Up to 100 per page.
pagenumberoptional- 1-based page number.
{
"success": true,
"data": {
"contacts": [
{
"id": "66f1c2a0d3b4e5f6a7b8c9d1",
"waId": "919876543210",
"name": "Priya Sharma",
"firstName": "Priya",
"lastName": "Sharma",
"email": "priya@acme.in",
"tags": [
"leads",
"diwali-2026"
],
"optedIn": true,
"blocked": false
}
],
"total": 412,
"page": 1,
"pages": 5
}
}Try it
/api/v1/integrations/motherbot/contacts?tag=leads&search=priya&limit=100&page=1Show as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/motherbot/contacts?tag=leads&search=priya&limit=100&page=1" \ -H "x-api-key: pk_live_your_key"
Check WhatsApp allowance
/api/v1/integrations/motherbot/usageAPI keyintegrations:read{
"success": true,
"data": {
"plan": "growth",
"subscriptionStatus": "active",
"active": true,
"rateLimitPerMinute": 300,
"messages": {
"key": "messagesPerMonth",
"label": "Messages",
"used": 8420,
"limit": 50000,
"unlimited": false,
"remaining": 41580,
"percentUsed": 17
}
}
}Try it
/api/v1/integrations/motherbot/usageShow as cURL
curl -X GET "https://pixbix.app/api/v1/integrations/motherbot/usage" \ -H "x-api-key: pk_live_your_key"
Send a render on WhatsApp
/api/v1/integrations/motherbot/messagesAPI keyintegrations:writeCost No pixbix credits. Consumes a conversation on your own MotherBot plan.
Body parameters
tostringrequired- How the chosen channel addresses somebody: a phone number for WhatsApp, SMS and RCS (international form, digits only — a leading zero, spaces and a “+” are cleaned up, and a number with no country code is refused rather than guessed at), an email address for email, or the platform id for a chat channel.
channelstringoptional- Defaults to whatsapp — the only channel that can open a conversation. A type the channel cannot carry is refused rather than silently downgraded.
accountIdstringoptional- Which connected identity to send from, from the channels endpoint. Defaults to the workspace’s default for the channel.
typestringoptional- template (default), text, image, video, document, audio or interactive.
templateNamestringrequired- An approved template. Required for template sends.
languageCodestringoptional- Only needed when one template name is approved in several languages.
renderIdstringoptional- A finished render in this workspace; its URL goes in the template’s media header.
mediaUrlstringoptional- Any public URL, if you would rather name the file directly — a render, a capture, or a file you host. Takes precedence over renderId. Its type must match what the template was approved for; a mismatch is refused here rather than per recipient by Meta.
variablesobjectoptional- Body variables by slot number: { "1": "Priya", "2": "AC-4192" }. Numbered, because WhatsApp fills them positionally.
textstringoptional- The message body, for type: "text".
subjectstringoptional- Required on the email channel; ignored elsewhere.
captionstringoptional- Shown under an image, video or document sent on its own. Audio carries no caption.
interactiveobjectoptional- For type: "interactive". Meta’s own shape: { type: "button" | "list" | "cta_url", body: { text }, header?, footer?, action }. Reply buttons cap at 3, list rows at 10 overall, and both are checked here rather than at Meta.
headerFilenamestringoptional- Filename shown for a document header. Derived from the URL when omitted, and ignored for image and video.
{
"to": "919876543210",
"templateName": "order_ready_video",
"renderId": "rnd_8fK2mQ",
"variables": {
"1": "Priya",
"2": "AC-4192"
}
}A send reaches a real person on WhatsApp and spends a conversation on your MotherBot plan, so it is not fired from the docs.
Broadcast a render on WhatsApp
/api/v1/integrations/motherbot/campaignsAPI keyintegrations:writeCost No pixbix credits. Consumes one conversation per recipient on your own MotherBot plan.
Body parameters
templateNamestringrequired- An approved template.
recipientsarrayrequired- Up to 5,000 per campaign. Each entry takes `to`, an optional `name`, and optional per-recipient `variables` that override the common ones.
namestringoptional- What the campaign is called in MotherBot. Defaults to “pixbix — <today>”.
languageCodestringoptional- Only needed when one template name is approved in several languages.
commonVariablesobjectoptional- Body variables shared by every recipient, by slot number: { "2": "50%" }.
renderIdstringoptional- A finished render in this workspace, used as the campaign’s media header.
mediaUrlstringoptional- A public URL instead of a render id.
rateLimitPerSecondnumberoptional- Messages a second. MotherBot’s own default is 3.
{
"name": "Diwali 2026 — video",
"templateName": "diwali_offer_video",
"renderId": "rnd_8fK2mQ",
"commonVariables": {
"2": "50%"
},
"recipients": [
{
"to": "919876543210",
"name": "Priya",
"variables": {
"1": "Priya"
}
},
{
"to": "919812345678",
"name": "Arjun",
"variables": {
"1": "Arjun"
}
}
]
}A campaign messages real people and spends a conversation per recipient on your MotherBot plan, so it is not fired from the docs.
Credits#
Current balance
/creditsSession token{
"success": true,
"data": {
"credits": {
"image": { "granted": 380, "topup": 500, "available": 880, "held": 2 },
"video": { "granted": 96, "topup": 250, "available": 346, "held": 15 }
},
"grants": { "imageCredits": 500, "videoCredits": 150 },
"periodEnd": "2026-09-01T00:00:00.000Z",
"planCode": "starter"
}
}held is reserved by renders currently in flight. It has already been removed from the balance — it is shown so you can explain a temporary dip.
Credit ledger
/credits/historySession tokenWebhooks#
Register endpoints in the dashboard under Settings → Webhooks, with the endpoints below, or set callback per render. All three receive the same payload.
A registered endpoint describes the whole request — method, body encoding, headers and the payload itself, all of which accept {{variables}} resolved per delivery. The reference for those settings is on the webhooks guide; everything below describes the default shape.
Managing endpoints
Endpoints can be registered and edited with a key as well as from the dashboard, so a deployment can point its own webhook at a fresh environment without anyone opening a browser. These take webhooks:read and webhooks:write.
secretHint, the last four characters, which is enough to tell two endpoints apart and useless to anyone else.List webhook endpoints
/api/v1/webhooksAPI keywebhooks:readQuery parameters
pagenumberoptional- Page number, from 1.
limitnumberoptional- Rows per page, 1–100. Defaults to 50.
sortstringoptional- Column to order by: createdAt, description, url, lastSuccessAt, lastFailureAt. Defaults to `createdAt`.
order"asc" | "desc"optional- Sort direction. Defaults to `desc` for dates and counts.
searchstringoptional- Case-insensitive match across description, url. Up to 128 characters.
isActivebooleanoptional- Restrict to live or paused endpoints.
eventsstringoptional- Only endpoints subscribed to these events, comma-separated.
{
"success": true,
"data": [
{
"id": "whk_3d81",
"url": "https://acme.example/hooks/pixbix",
"description": "Production",
"events": [
"render.completed",
"render.failed",
"render.cancelled"
],
"method": "POST",
"bodyFormat": "json",
"payloadMode": "default",
"secretHint": "whsec_…8f2a",
"isActive": true,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-08-15T09:41:02.118Z"
}
]
}Try it
/api/v1/webhooks?page=1&limit=50&sort=createdAt&order=desc&search=diwali&isActive=true&events=render.completedShow as cURL
curl -X GET "https://pixbix.app/api/v1/webhooks?page=1&limit=50&sort=createdAt&order=desc&search=diwali&isActive=true&events=render.completed" \ -H "x-api-key: pk_live_your_key"
Register a webhook endpoint
/api/v1/webhooksAPI keywebhooks:writeBody parameters
urlstringrequired- Absolute HTTPS URL. May contain {{variables}}, resolved per delivery.
descriptionstringoptional- Your own label. Up to 200 characters.
eventsstring[]optional- Defaults to the three terminal endings: render.completed, render.failed and render.cancelled.
method"POST" | "PUT" | "PATCH" | "GET"optional- Defaults to POST.
bodyFormat"json" | "form" | "multipart" | "none"optional- How the body is encoded. Defaults to json.
payloadMode"default" | "custom"optional- Send our event envelope, or your own body built from {{variables}}.
payloadTemplatestringoptional- The custom body, when payloadMode is custom. Required in that case.
headers{ key, value }[]optional- Up to 20 extra request headers. Values accept {{variables}}.
{
"url": "https://acme.example/hooks/pixbix",
"description": "Production",
"events": [
"render.completed",
"render.failed",
"render.cancelled"
]
}Creating an endpoint returns a secret that is shown once; run it from your own client so the response is not left in a browser tab.
Update a webhook endpoint
/api/v1/webhooks/:idAPI keywebhooks:writePath parameters
idstringrequired- Webhook endpoint id.
Body parameters
isActivebooleanoptional- Pause or resume deliveries.
urlstringoptional- Absolute HTTPS URL.
eventsstring[]optional- Replaces the subscribed event list.
method"POST" | "PUT" | "PATCH" | "GET"optional- HTTP method used for delivery.
bodyFormat"json" | "form" | "multipart" | "none"optional- Body encoding.
payloadMode"default" | "custom"optional- Our envelope, or your own body.
payloadTemplatestringoptional- The custom body, when payloadMode is custom.
headers{ key, value }[]optional- Replaces the extra header list.
{
"events": [
"render.completed"
],
"isActive": true
}Editing a live endpoint changes where your production events go.
Send a test event
/api/v1/webhooks/:id/testAPI keywebhooks:writePath parameters
idstringrequired- Webhook endpoint id.
{
"success": true,
"message": "Delivered — your endpoint replied 200.",
"data": {
"ok": true,
"status": 200
}
}A test delivery hits your own server; fire it from a client you control.
Delete a webhook endpoint
/api/v1/webhooks/:idAPI keywebhooks:writePath parameters
idstringrequired- Webhook endpoint id.
{
"success": true,
"message": "Webhook deleted",
"data": null
}Deleting an endpoint stops production deliveries.
Events
| Event | Fired when |
|---|---|
render.queued | A render is accepted into the queue |
render.started | A worker picks it up |
render.completed | The output is stored and ready |
render.failed | The render failed; credits refunded |
template.published | A template passed review |
credits.low | Balance falls below the warning threshold |
credits.exhausted | Balance reaches zero |
subscription.updated | Plan or subscription status changed |
payment.captured | A payment succeeded |
Default payload
{
"id": "evt_m1x8k2p9",
"type": "render.completed",
"created": "2026-08-13T09:15:48.221Z",
"data": {
"id": "rnd_8f2a1c",
"status": "done",
"kind": "video",
"templateId": "story-reel",
"url": "https://cdn.pixbix.app/render/…/render.mp4",
"posterUrl": "https://cdn.pixbix.app/render/…/poster.jpg",
"thumbnailUrl": "https://cdn.pixbix.app/render/…/thumbnail.jpg",
"format": "mp4",
"width": 1080,
"height": 1920,
"duration": 15.02,
"fileSizeBytes": 2841022,
"renderTime": 42180,
"credits": 15,
"watermarked": false,
"expiresAt": "2026-09-12T09:15:48.221Z"
}
}Verifying the signature
Every delivery carries these headers:
X-Pixbix-Event: render.completed
X-Pixbix-Timestamp: 1786000548
X-Pixbix-Signature: sha256=9f2c…
X-Pixbix-Attempt: 1The signature is an HMAC-SHA256 over `${timestamp}.${rawBody}` using your endpoint secret. Including the timestamp in the signed string is what prevents a captured payload being replayed later.
import crypto from "crypto";
// IMPORTANT: verify against the RAW body. Re-serialising a parsed body
// changes key order and whitespace, and the signature will never match.
app.post("/hooks/pixbix", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.get("X-Pixbix-Timestamp");
const signature = req.get("X-Pixbix-Signature");
// Reject anything older than five minutes.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.status(400).send("stale");
}
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.PIXBIX_WEBHOOK_SECRET)
.update(timestamp + "." + req.body.toString())
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send("bad signature");
}
const event = JSON.parse(req.body.toString());
// Acknowledge fast, then do the work asynchronously.
res.sendStatus(200);
void handle(event);
});Respond quickly
Return2xx within 10 seconds and do the work afterwards. Non-2xx responses are retried with backoff up to 5 times; an endpoint that keeps failing is disabled automatically after 20 consecutive failures.Managing endpoints
The dashboard form writes through these. They take a session token and X-Pixbix-Org, not an API key — script them when you are provisioning several workspaces and would rather not fill the same form in repeatedly.
List endpoints
/organization/webhooksSession tokenCreate an endpoint
/organization/webhooksSession tokenParameters
urlstringrequired- HTTPS in production. May contain {{variables}}.
eventsstring[]required- Which events to subscribe to.
descriptionstringoptional- Free text, for your own reference.
methodstringoptional- POST (default), PUT, PATCH or GET.
bodyFormatstringoptional- json (default), form, multipart or none. Forced to none for GET.
payloadModestringoptional- default sends our envelope; custom sends payloadTemplate.
payloadTemplatestringoptional- A JSON object, as text, holding {{variables}}. Required when payloadMode is custom; rejected if it is not valid JSON.
headersarrayoptional- Up to 20 { key, value } pairs sent with every delivery. Values take variables; X-Pixbix-* headers cannot be overridden.
{
"url": "https://api.acme.com/hooks/pixbix",
"events": ["render.completed", "render.failed"],
"method": "POST",
"bodyFormat": "json",
"payloadMode": "custom",
"payloadTemplate": "{\"renderId\": \"{{data.id}}\", \"fileUrl\": \"{{data.url}}\"}",
"headers": [{ "key": "Authorization", "value": "Bearer your-receiver-token" }]
}Update an endpoint
/organization/webhooks/{id}Session tokenSend a test event
/organization/webhooks/{id}/testSession tokenDelete an endpoint
/organization/webhooks/{id}Session token