List jobs
Retrieve a paginated, filterable list of moderation jobs for your account.
https://api.omnifence.ai/api/v1/jobsRequires the job:read scope. Requests without this scope receive a 403 FORBIDDEN response. See
authentication.
Jobs are returned newest-first (created_at descending) and scoped to your account. Use limit
(max 100) and offset to page through results; total in the response is the unpaginated count.
Filters#
| Parameter | Description |
|---|---|
type |
Job modality: text, image, video, or audio. generate, pre, post and chat are non-moderation or retired values, kept so historical jobs stay filterable. |
decision |
Moderation outcome: pass or reject. |
status |
Job status. See below. |
search |
Prefix-match on job_id. |
api_key_id |
The API key a job was submitted with. Pass none for the jobs with no key. See below. |
from |
Inclusive lower bound on created_at (ISO 8601). |
to |
Exclusive upper bound on created_at (ISO 8601). |
API key attribution#
Each job submitted with an API key records that key. Each row in the response carries api_key_id
and api_key_name, so you can split traffic by key. For example, you can use one key per
environment, customer, or service without keeping your own mapping.
Both fields are null on a job that no key submitted: one sent from the dashboard, and any job
created before key attribution shipped. Filter to exactly those with api_key_id=none.
api_key_name is resolved when you read the job, not stored on it. A key you renamed shows its
current name on every past job, and a key you deleted resolves to null. api_key_id is stored on
the job and never changes, so it stays correct in both cases. Use the id as the stable identifier.
Status filter#
status accepts a comma-separated list of one or more job statuses:
| Status | Meaning |
|---|---|
queued |
Accepted and being moderated. |
processing |
Reserved. No moderation job reports it today. |
completed |
Finished. See is_prohibited for the outcome. |
failed |
Terminated with an error before a decision. |
A moderation job stays queued for its whole run and then flips straight to completed or
failed; it never reports processing. queued and processing are both in-flight states and
completed and failed are terminal, so request both in-flight values to stay correct if that
changes:
GET /api/v1/jobs?status=queued,processing
An unknown status value returns 400 INVALID_REQUEST.
Polling for completion#
Webhooks are the primary, low-latency way to learn that a job finished. Register one when you submit, or via register webhook. Webhook delivery is best-effort, so use this endpoint as a cheap reconciliation safety net rather than your primary signal:
- Poll
GET /api/v1/jobs?status=queued,processingon an interval. One request covers every outstanding job, regardless of how many you have in flight. That is far cheaper than polling each job individually with get job status. - A job that drops out of the in-flight list has reached a terminal state. Fetch the terminal set
(
status=completed,failed, optionally narrowed withfrom) to pick up any outcome whose webhook was missed. - Keep the interval modest. Every request counts toward your rate limit. Webhooks carry the fast path; reconciliation only needs to catch stragglers.
Example#
curl -G "https://api.omnifence.ai/api/v1/jobs" \
-H "Authorization: Bearer $API_KEY" \
--data-urlencode "status=queued,processing" \
--data-urlencode "limit=100"
Request#
Headers#
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Yes | Your API key as a Bearer token: Bearer YOUR_API_KEY. |
Query parameters#
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer | No | Default 50. Min 1, max 100. |
offset |
integer | No | Default 0. Min 0. |
type |
string | No | Filter by job modality. text, image, video, audio are the active moderation modalities. generate and pre/post/chat are non-moderation or retired types, kept so historical jobs stay filterable. One of pre, post, chat, text, image, video, audio, generate. |
decision |
string | No | Filter by moderation decision. One of pass, reject. |
status |
string | No | Filter by job status. Comma-separated list of: queued, processing, completed, failed. Example: status=queued,processing returns all in-flight jobs, which is useful for low-cost reconciliation polling alongside webhooks. |
search |
string | No | Prefix-match filter on job_id. Length max 64. |
api_key_id |
string | No | Filter to jobs submitted with a single API key. Pass the key id, or the literal none to return only the jobs with no key attribution (dashboard submissions and jobs created before key attribution shipped). Length max 128. |
from |
string (date-time) | No | Inclusive lower bound on job created_at (ISO 8601). |
to |
string (date-time) | No | Exclusive upper bound on job created_at (ISO 8601). |
Responses#
200 OK#
| Field | Type | Always present | Description |
|---|---|---|---|
jobs |
array of object | Yes | |
jobs[].is_prohibited |
null or boolean | Yes | |
jobs[].job_id |
string (uuid) | Yes | |
jobs[].type |
string | Yes | One of pre, post, chat, text, image, video, audio, generate. |
jobs[].status |
string | Yes | One of queued, processing, completed, failed. |
jobs[].api_key_id |
null or string | Yes | Id of the API key the job was submitted with. Null for jobs submitted from a dashboard session, and for jobs created before key attribution shipped. |
jobs[].api_key_name |
null or string | Yes | Display name of that API key, resolved at read time. Null when the key was never named or has since been deleted. api_key_id still identifies it. |
jobs[].created_at |
string (date-time) | Yes | |
jobs[].completed_at |
null or string (date-time) | Yes | |
total |
integer | Yes | |
limit |
integer | Yes | |
offset |
integer | Yes |
{
"jobs": [
{
"is_prohibited": false,
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "pre",
"status": "queued",
"api_key_id": "string",
"api_key_name": "string",
"created_at": "2026-05-19T12:00:00.000Z",
"completed_at": "2026-05-19T12:00:00.000Z"
}
],
"total": 0,
"limit": 0,
"offset": 0
}