API reference

Clear an asset
from your own code.

Everything the portal does by hand, a request can do too — the same frameworks, the same rulings, the same clause-level reasoning. Two calls take an asset from upload to verdict.

Base URL
https://api.voxlyvision.com/api
Authentication
X-API-Key: $VOXLY_API_KEY
The loop

Upload, poll, read the ruling

A human still makes the call. The API hands them the clause, the reason and the fix — already on the page.

  1. 01

    Submit the assets

    POST /v1/evaluations as multipart form data: a name, the frameworks to judge against, and the files themselves. The evaluation id comes back immediately.

  2. 02

    Poll the evaluation

    GET /v1/evaluations/{evaluationId} returns the batch's status and, once it is completed, the section-by-section ruling for every asset in it.

  3. 03

    Zoom into one asset

    Each file in a batch is a job. GET /v1/jobs/{id} reads a single one back on its own, with the clause each finding cites.

  4. 04

    Work with what is already there

    Frameworks, assets and uploads are reachable too — list what you can judge against, browse the media already in the workspace, or send a large file straight to storage.

Authentication

One key, one header

Keys are workspace-scoped and made in the portal under Settings → API keys. Every v1 route reads the same header; a bearer token is the web session's and will not work here.

Every request
X-API-Key: $VOXLY_API_KEY
Reference

11 endpoints

Frameworks are read-only: they are authored, versioned and approved in the portal, and the API reads their ids and sections back.

Evaluations

POST /v1/evaluations

Starts an evaluation of one or more assets against the frameworks you name.

Multipart, not JSON — the assets can travel in the same request. Repeat the frameworkIds and files fields to send more than one. You supply the assets exactly one way per request: inline, from the upload flow, from assets already in the workspace, or from urls Voxly Vision fetches. Each of the four is shown below. The work is queued: the response returns as soon as it is accepted, and each asset becomes its own job. Limits are 5 assets and 3 frameworks per request, 500 MB per file.

Parameters

namestringrequired
Labels the batch in the workspace.
frameworkIdsuuid[]required
One field per framework the assets are judged against, 3 at most. Get the ids from GET /v1/frameworks.GET /v1/frameworks
filesfile[]optional
The assets themselves. One field per file, 5 per request, 500 MB each.Content types
uploadIdsuuid[]optional
Instead of files. Ids from POST /v1/uploads whose bytes you already sent to storage; the evaluation completes the upload for you.POST /v1/uploads
assetIdsuuid[]optional
Instead of files. Re-runs assets already in the workspace; nothing is uploaded and they keep their folder.GET /v1/assets
fileUrlsstring[]optional
Instead of files. Public https urls Voxly Vision downloads itself — http is refused, as are private, loopback and link-local addresses. 500 MB per file, 8192 characters per url.
labelIduuidoptional
Files newly created assets into a folder. Ignored for assetIds re-runs, which keep the folder they already have.
idempotencyKeyuuidoptional
Reusing one returns the original batch instead of running — and charging — twice.

5 ways to call this

Send the file with the request

The simplest form. The asset is uploaded and evaluated in one call.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/evaluations" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F files=@hero.png

Use an upload you already sent

For large media. Request an upload url, PUT the bytes to storage, then name the uploadId here — the evaluation turns it into an asset for you, so the completion call is not needed.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/evaluations" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F uploadIds="e41b8d6a-2c95-4f38-90b7-3a5d6e2f7c18"

Re-run an asset already in the workspace

Nothing is uploaded. Use this to judge existing media against a new framework, or against a newer version of the same one.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/evaluations" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -F name="Portman v3 re-run" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F assetIds="3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93"

Have us fetch the file from a url

For assets that already live somewhere public — a CDN, a signed link from your DAM. https only, and internal addresses are refused.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/evaluations" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F fileUrls="https://cdn.example.com/spring/hero.png"

File into a folder safely

A destination folder and an idempotency key so a retry cannot charge twice.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/evaluations" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F files=@hero.png \
  -F labelId="7b2e9c04-1f83-4a55-9d61-0c8e3b5a2f47" \
  -F idempotencyKey="9f14c8a2-6d30-4b7e-8a51-2e9c4f0b6d83"
Response
{
  "evaluationId": "6b21f8ad-3f4e-4c7a-9f10-2b8d5c1e04a7",
  "status": "pending",
  "jobs": [
    {
      "id": "b7d4c2f1-90ae-4d63-8c25-1a6f7e930bd4",
      "status": "pending",
      "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
      "assetName": "spring-campaign-hero.jpg"
    }
  ]
}

GET /v1/evaluations/{evaluationId}

Reads the whole batch back — the status of the evaluation and the results of every job in it.

This is the endpoint to poll. While work is outstanding the status stays pending or processing; once it reads completed, every job carries its section results. A job that could not be evaluated reports failed with a failureCode.

Parameters

evaluationIduuidrequired
Path parameter. The id returned by POST /v1/evaluations.
Request
curl -X GET "https://api.voxlyvision.com/api/v1/evaluations/{evaluationId}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "evaluationId": "6b21f8ad-3f4e-4c7a-9f10-2b8d5c1e04a7",
  "status": "completed",
  "jobs": [
    {
      "jobId": "b7d4c2f1-90ae-4d63-8c25-1a6f7e930bd4",
      "assetName": "spring-campaign-hero.jpg",
      "status": "completed",
      "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
      "results": [
        {
          "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
          "frameworkName": "Portman",
          "status": "completed",
          "classification": "non_compliant",
          "justification": "Clause 3.2(b) — the drinking scene precedes the product shot.",
          "voxlyInsights": null,
          "error": null
        }
      ]
    }
  ]
}
Jobs

GET /v1/jobs/{id}

Reads one job — a single asset's ruling, section by section, with the reasoning behind each one.

A job is one asset inside an evaluation. Each section result carries a classification, the justification for it, a recommendation where one applies, and the framework section it was judged against.

Parameters

iduuidrequired
Path parameter. A jobId from the evaluation's jobs array.
Request
curl -X GET "https://api.voxlyvision.com/api/v1/jobs/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "jobId": "b7d4c2f1-90ae-4d63-8c25-1a6f7e930bd4",
  "status": "completed",
  "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
  "assetName": "spring-campaign-hero.jpg",
  "results": [
    {
      "resultId": "9e5b3d21-7c48-4a6f-b0d9-2f8e1c4a6b57",
      "status": "completed",
      "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
      "frameworkName": "Portman",
      "classification": "non_compliant",
      "justification": "Clause 3.2(b) — the drinking scene precedes the product shot.",
      "voxlyInsights": null,
      "error": null,
      "sections": [
        {
          "sectionId": "5a2c7e90-3b16-4d82-9f4a-8c0e5b7d1a63",
          "sectionTitle": "Consumption",
          "subsectionTitle": "Order of depiction",
          "classification": "non_compliant",
          "justification": "The pour is shown before the pack shot.",
          "recommendation": "Re-cut so the product is established first."
        }
      ]
    }
  ]
}

DELETE /v1/jobs/{id}

Deletes a job and the ruling it produced.

The asset the job ran on is left alone — deleting a job removes the evaluation of it, not the media. Delete the asset separately if you want both gone.

Parameters

iduuidrequired
Path parameter. The job to delete.
Request
curl -X DELETE "https://api.voxlyvision.com/api/v1/jobs/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "jobId": "b7d4c2f1-90ae-4d63-8c25-1a6f7e930bd4",
  "status": "deleted"
}
Assets

GET /v1/assets

Lists the media in the workspace, newest or oldest first.

Answers with a bare array rather than a paginated envelope, so there is no total to read — ask for the next page until one comes back with fewer rows than the limit. Defaults are page 1, limit 10, oldest first.

Parameters

pagenumberoptional
1-based. Defaults to 1.
limitnumberoptional
Rows per page. Defaults to 10.
orderstringoptional
Sorts by upload date. Defaults to asc.ascdesc
qstringoptional
Filters by file name, case-insensitive substring.
labelIdsstringoptional
Comma-separated folder ids. An asset matching any of them is returned.
ownedbooleanoptional
Restricts the list to assets this API key uploaded.truefalse

3 ways to call this

Newest first

The first page of the library, most recent upload first.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/assets?page=1&limit=10&order=desc" \
  -H "X-API-Key: $VOXLY_API_KEY"

Search by file name

Substring match, case-insensitive. Remember to url-encode the term.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/assets?q=spring&order=desc" \
  -H "X-API-Key: $VOXLY_API_KEY"

One folder, uploaded by this key

Folder ids are asset-scope labels; the portal calls them folders.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/assets?labelIds=7b2e9c04-1f83-4a55-9d61-0c8e3b5a2f47&owned=true" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
[
  {
    "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
    "fileName": "spring-campaign-hero.jpg",
    "fileType": "image",
    "fileExtension": "jpg",
    "createdAt": "2026-08-04T09:12:44.108Z",
    "updatedAt": "2026-08-04T09:12:44.108Z",
    "createdBy": "0c7f1e52-84ab-4d90-9f31-5b6c2a7e8d40"
  }
]

GET /v1/assets/{id}

Reads one asset's metadata.

Metadata only — the media itself is not served here. `createdBy` is whichever principal uploaded it: a user id for a portal upload, an API key id for one of yours.

Parameters

iduuidrequired
Path parameter. An assetId from a list, an upload completion, or a job.
Request
curl -X GET "https://api.voxlyvision.com/api/v1/assets/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
  "fileName": "spring-campaign-hero.jpg",
  "fileType": "image",
  "fileExtension": "jpg",
  "createdAt": "2026-08-04T09:12:44.108Z",
  "updatedAt": "2026-08-04T09:12:44.108Z",
  "createdBy": "0c7f1e52-84ab-4d90-9f31-5b6c2a7e8d40"
}

DELETE /v1/assets/{id}

Deletes an asset from the workspace.

Removes the media. Jobs that already evaluated it keep their rulings, so a report stays readable after the asset behind it is gone.

Parameters

iduuidrequired
Path parameter. The asset to delete.
Request
curl -X DELETE "https://api.voxlyvision.com/api/v1/assets/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
  "status": "deleted"
}
Frameworks

GET /v1/frameworks

Lists the frameworks this workspace can evaluate against — its own and the global ones.

One row per framework family, carrying whichever version is current. Frameworks are read-only over the API: they are authored, versioned and approved in the portal, and the ids you collect here are what you pass to frameworkIds when you start an evaluation.

Parameters

typestringoptional
Whose framework it is.globalcustomFramework type
statusstringoptional
Ask for live unless you have a reason not to — a draft or deprecated framework is not something to judge against.pendingprocessingdraftlivedeprecatedfailedFramework status

2 ways to call this

Everything you can evaluate against

The usual call: live frameworks, both the global codes and this workspace's own.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/frameworks?status=live" \
  -H "X-API-Key: $VOXLY_API_KEY"

This workspace's own frameworks

Custom frameworks only, authored in the portal.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/frameworks?type=custom&status=live" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
[
  {
    "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
    "frameworkName": "Portman",
    "description": "UK alcohol advertising code.",
    "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
    "type": "global",
    "status": "live",
    "version": 3,
    "isLatest": true,
    "sectionCount": 12
  }
]

GET /v1/frameworks/{id}

Reads one framework in full, including every section an evaluation will judge against.

The sections are the framework's substance: each carries the rules text, whether it applies to every asset, and the description that decides applicability when it does not. This is the endpoint to read if you want to explain a ruling in your own interface.

Parameters

iduuidrequired
Path parameter. A frameworkId from the list endpoint.
Request
curl -X GET "https://api.voxlyvision.com/api/v1/frameworks/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
  "frameworkName": "Portman",
  "description": "UK alcohol advertising code.",
  "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
  "type": "global",
  "version": 3,
  "isLatest": true,
  "status": "live",
  "createdAt": "2026-05-19T11:03:21.884Z",
  "updatedAt": "2026-07-02T16:40:07.552Z",
  "sections": [
    {
      "sectionId": "5a2c7e90-3b16-4d82-9f4a-8c0e5b7d1a63",
      "sectionTitle": "Consumption",
      "subsectionTitle": "Order of depiction",
      "rules": "The product must be established before consumption is shown.",
      "alwaysApplicable": true
    }
  ]
}
Uploads

POST /v1/uploads

Asks for a presigned url so you can send a file straight to storage.

Step one of three. Describe the file here, PUT the bytes to the uploadUrl that comes back, then either call the completion endpoint or pass the uploadId to POST /v1/evaluations, which completes it for you. Large media never passes through the API this way. The url expires, so request it when you are ready to send.

Parameters

fileNamestringrequired
The name the asset will carry in the workspace.
contentTypestringrequired
Must match what you actually PUT to the url.image/jpegimage/pngvideo/mp4text/plainContent types
fileSizenumberrequired
Bytes, up to 500 MB. Declared up front so the url can be signed for it.

3 ways to call this

An image

A 2 MB png. The response carries the url to PUT it to.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/uploads" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"hero.png","contentType":"image/png","fileSize":2048576}'

A film

Video is where this flow earns its keep — the bytes never pass through the API.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/uploads" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"launch-film.mp4","contentType":"video/mp4","fileSize":184549376}'

Step 2 — send the bytes

Not one of ours: a plain PUT to the uploadUrl returned above. The Content-Type must match what you declared.

Request
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/png" \
  --data-binary @hero.png
Response
{
  "uploads": [
    {
      "uploadId": "e41b8d6a-2c95-4f38-90b7-3a5d6e2f7c18",
      "uploadUrl": "https://s3.eu-west-2.amazonaws.com/...",
      "expiresAt": "2026-08-10T14:22:05.331Z"
    }
  ]
}

POST /v1/uploads/{uploadId}/complete

Turns a finished upload into an asset in the workspace.

Step three, and optional: call it once the PUT has succeeded to get the asset back, or skip it entirely and pass the uploadId to POST /v1/evaluations, which completes the upload itself. There is no request body.

Parameters

uploadIduuidrequired
Path parameter, from POST /v1/uploads. No body is required.
Request
curl -X POST "https://api.voxlyvision.com/api/v1/uploads/{uploadId}/complete" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "assetId": "3c9a1b70-52d8-4e11-bb7f-6d2c8a4f1e93",
  "createdAt": "2026-08-10T14:19:52.006Z",
  "updatedAt": "2026-08-10T14:19:52.006Z",
  "fileName": "spring-campaign-hero.jpg",
  "fileType": "image",
  "fileExtension": "jpg"
}
Vocabulary

Every value the API will give you

Closed sets, read from the platform's own definitions. If a field is documented as a string and appears here, these are the only values it takes.

Classification

The ruling on a section, and on the framework result as a whole.

compliant
The asset satisfies the section.
non_compliant
The asset breaches the section.
non_applicable
The section does not apply to this asset.

Job status

Carried by a job and by each framework result inside it.

pending
Accepted and queued; no work started.
processing
Being evaluated now.
completed
Finished; results are readable.
failed
Stopped early; read `error` for the reason.

Failure codes

The `error` field on a framework result, set when its status is failed.

unknown_failure
Unclassified failure.
image_extraction_failed
The media could not be read — wrong format, or corrupt.
applicability_check_failed
Could not decide which sections applied to the asset.
section_evaluations_failed
The per-section rulings did not complete.
overall_justification_failed
Sections were judged but the summary could not be written.
supplemental_insights_failed
The ruling stands; only the optional insights failed.

Framework status

Only a live framework is worth evaluating against.

pending
Queued for processing after upload.
processing
Being parsed into sections.
draft
Authored but not yet approved.
live
Approved — evaluate against this one.
deprecated
Superseded by a newer version.
failed
Could not be parsed.

Framework type

global
The codes we maintain — Portman, DISCUS, ASA, TTB.
custom
Authored by your workspace.

Asset content types

What an asset may be. Framework documents (pdf) and branding images (webp, svg) use different routes and are rejected by an evaluation.

image/jpeg
Still image (.jpg, .jpeg).
image/png
Still image (.png).
video/mp4
Film (.mp4).
text/plain
Copy (.txt).