API reference
Integrate the SaliencyLab creative analysis API: upload media, submit asynchronous jobs, handle limits, and verify signed webhooks.
The SaliencyLab API supports workspace-scoped, asynchronous creative analysis. Manage keys from Settings → API inside the authenticated workspace.
Private preview: REST analysis writes and webhook delivery are currently in private preview. Test keys return deterministic fixtures for integration development. Live-key write requests can return
503when live processing is not enabled, without consuming quota.
Authentication
Send a key with either header:
Authorization: Bearer sl_live_xxx
x-api-key: sl_live_xxx
Keys beginning with sl_test_ return deterministic fixtures and do not invoke the live analysis pipeline.
If both supported headers are present, the Bearer token takes precedence. Do not use the generic apikey header from a Supabase client; SaliencyLab keys use the sl_live_ or sl_test_ format.
Integration flow
Large media should not pass through your application server or a Vercel request body. The API uses a direct-upload sequence:
- Call
POST /v1/uploadswith file metadata to obtain a signed storage upload URL. - Upload the bytes directly to that signed URL.
- Call
POST /v1/analyseswith the returnedstorage_pathand creative context. - Store the returned job ID.
- Poll
GET /v1/analyses/{job_id}untilcompleteorfailed, or provide a webhook URL.
Video upload requests must include a positive duration_seconds value no greater than the documented limit. The processing worker measures duration again before analysis.
Submit an analysis
const headers = {
Authorization: `Bearer ${process.env.SALIENCYLAB_API_KEY}`,
'Content-Type': 'application/json',
};
const uploadResponse = await fetch('https://api.saliencylab.com/v1/uploads', {
method: 'POST',
headers,
body: JSON.stringify({
filename: 'creative.mp4',
content_type: 'video/mp4',
size_bytes: file.size,
duration_seconds: 15,
}),
});
const upload = await uploadResponse.json();
await fetch(upload.data.upload_url, {
method: 'PUT',
headers: { 'Content-Type': 'video/mp4' },
body: file,
});
const response = await fetch('https://api.saliencylab.com/v1/analyses', {
method: 'POST',
headers,
body: JSON.stringify({
storage_path: upload.data.storage_path,
platform: 'youtube',
market: 'US',
}),
});
const analysis = await response.json();
const jobId = analysis.data.job_id;
Check every HTTP status and the response envelope before reading data. JSON responses use { success, data, error, meta }.
Main endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/uploads | Mint a signed direct-upload URL |
| POST | /v1/analyses | Submit one creative for analysis |
| GET | /v1/analyses | List analyses in the workspace |
| GET | /v1/analyses/{job_id} | Read status or the completed result |
| DELETE | /v1/analyses/{job_id} | Delete an analysis and its assets |
| POST | /v1/analyses/batch | Submit a batch of creatives |
| GET | /v1/analyses/batch/{batch_id} | Read batch status |
| GET | /v1/benchmarks | Read supported benchmark context |
| GET | /v1/creative-drivers | Read creative attribute drivers |
Job states and polling
Analysis jobs move through queued, running, complete, or failed. Batch responses can also be partial. Poll with bounded backoff, honor rate-limit headers, and stop on a terminal state. Do not resubmit a creative merely because a job remains queued or running.
Errors and rate limits
Failure envelopes include a stable error code and message. Handle at least:
400for invalid metadata, unsupported media, or unsafe webhook URLs401for a missing or invalid API key403for plan or workspace restrictions404when a resource is absent from the authenticated workspace429when a minute or monthly limit is reached503when private-preview live processing is unavailable
Use the X-RateLimit-* response headers for live counters and retry timing. Do not infer quota consumption from the number of client attempts.
Webhooks
When you supply a webhook URL, verify X-SaliencyLab-Signature against the raw request body using the one-time signing secret returned at submission. Reject the delivery if verification fails.
Compute a hex HMAC-SHA256 digest over the untouched request bytes and compare signatures in constant time. Store the signing secret when the job is created; it is returned once. Make webhook handling idempotent because deliveries can be retried.
Webhook URLs must use HTTPS and pass SaliencyLab's public-network safety checks. Redirects to local, private, or link-local addresses are rejected.
Security checklist
- Keep live keys in a server-side secret manager.
- Never expose a key in browser code, logs, screenshots, or source control.
- Scope every stored job ID to the workspace associated with the key.
- Verify webhooks before parsing or acting on their contents.
- Rotate and revoke keys from workspace settings when exposure is suspected.
- Use a test key for CI and integration demos.
Download the machine-readable OpenAPI specification.