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

17 endpoints

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

Usage

GET /v1/usage

Returns this workspace's current credit usage and balance.

Use this to show the current plan, consumption during its billing period, and the remaining balance including any top-ups.

Request
curl -X GET "https://api.voxlyvision.com/api/v1/usage" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "used": 200,
  "remaining": 50,
  "billingEndDate": "2026-10-01T00:00:00.000Z",
  "currentPlan": "Spark"
}
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 the selected asset-source field to send more than one. Choose exactly one asset source: files, uploadIds, assetIds, or fileUrls. Do not combine them in the same request. Each option 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 →

Choose exactly one asset source

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. Use the frameworkId to read, update a draft, or approve a framework; use frameworkGroupId to create its next version. Live frameworkIds 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
    }
  ]
}

POST /v1/frameworks

Creates a custom framework from sections you provide.

The framework starts as a draft. Define at least one section, then approve it when it is ready to evaluate against. Custom is the default frameworkType; global frameworks are reserved for authorised administrators.

Parameters

namestringrequired
The framework's display name.
industrystringrequired
The industry this framework covers, for example general or alcohol.
marketsstring[]required
One to ten markets, such as global, united_kingdom, or united_states. global cannot be combined with another market.
sectionsobject[]optional
The rules to evaluate. The object schema is detailed below.
sections[].sectionTitlestringrequired
Title of this rule section.
sections[].rulesstringrequired
The rules Voxly Vision should evaluate against.
sections[].alwaysApplicablebooleanrequired
true when this section applies to every asset; otherwise false.
sections[].subsectionTitlestringoptional
Optional subheading within the section.
sections[].applicabilityDescriptionstringoptional
Optional explanation of when a section that is not always applicable should apply.
descriptionstringoptional
Optional explanation of the framework.

Create a draft framework

Supply the rules in the request, then approve the returned frameworkId when it is ready.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/frameworks" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Brand safety","industry":"general","markets":["global"],"description":"Internal marketing guidance.","sections":[{"sectionTitle":"Truthful claims","rules":"Claims must be accurate and substantiated.","alwaysApplicable":true}]}'
Response
{
  "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
  "frameworkName": "Brand safety",
  "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
  "frameworkType": "custom",
  "markets": ["global"],
  "industry": "general",
  "status": "draft",
  "version": 1,
  "isLatest": true,
  "createdAt": "2026-09-11T09:12:44.108Z",
  "updatedAt": "2026-09-11T09:12:44.108Z",
  "sections": []
}

POST /v1/frameworks/upload

Creates a framework by fetching a document from the web.

API framework upload currently supports web_upload only. Send a public document URL in frameworkUrl; file_upload and multipart PDF uploads are not supported through this API at this time. The response is pending while the document is processed into sections.

Parameters

namestringrequired
The framework's display name.
industrystringrequired
The industry this framework covers, for example general or alcohol.
marketsstring[]required
One to ten markets. global cannot be combined with another market.
uploadMethodstringrequired
Must be web_upload. file_upload is not currently supported via the API.
frameworkUrlstringrequired
Public URL of the framework document Voxly Vision should fetch.
supplementalDomainsstring[]optional
Optional supporting domains, up to three.

Upload from a public document URL

web_upload is the only API upload method today; do not send a file or s3Key.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/frameworks/upload" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Brand safety","industry":"general","markets":["global"],"uploadMethod":"web_upload","frameworkUrl":"https://example.com/brand-safety.pdf","supplementalDomains":["https://example.com"]}'
Response
{
  "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
  "frameworkName": "Brand safety",
  "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
  "status": "pending"
}

POST /v1/frameworks/{id}/approve

Makes a draft framework available for evaluations.

Only a draft framework can be approved. There is no request body; global frameworks additionally require administrator access.

Parameters

iduuidrequired
Path parameter. The draft frameworkId to approve.
Request
curl -X POST "https://api.voxlyvision.com/api/v1/frameworks/{id}/approve" \
  -H "X-API-Key: $VOXLY_API_KEY"
Response
{
  "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
  "status": "live"
}

POST /v1/frameworks/{id}/versions

Creates the next version of a framework family.

Pass the frameworkGroupId from a framework response as id, not the frameworkId. A new version preserves prior evaluations on their original version; a live current version is superseded and the new version starts as a draft when sections are supplied.

Parameters

iduuidrequired
Path parameter. The frameworkGroupId of the family to version.
sectionsobject[]optional
Replacement rules for the new version. The object schema is detailed below.
sections[].sectionTitlestringrequired
Title of this rule section.
sections[].rulesstringrequired
The rules Voxly Vision should evaluate against.
sections[].alwaysApplicablebooleanrequired
true when this section applies to every asset; otherwise false.
sections[].subsectionTitlestringoptional
Optional subheading within the section.
sections[].applicabilityDescriptionstringoptional
Optional explanation of when a section that is not always applicable should apply.
name, industry, markets, description, supplementalDomainsmixedoptional
Optional replacements for the family metadata; omitted fields keep their current values.

Revise its rules

Use the frameworkGroupId returned by the list or detail response.

Request
curl -X POST "https://api.voxlyvision.com/api/v1/frameworks/{id}/versions" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"Updated rules for 2026","sections":[{"sectionTitle":"Truthful claims","rules":"Claims must be accurate, current and substantiated.","alwaysApplicable":true}]}'
Response
{
  "frameworkId": "7b6f1e52-84ab-4d90-9f31-5b6c2a7e8d40",
  "frameworkName": "Brand safety",
  "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
  "frameworkType": "custom",
  "markets": ["global"],
  "industry": "general",
  "status": "draft",
  "version": 2,
  "isLatest": true,
  "createdAt": "2026-09-11T10:12:44.108Z",
  "updatedAt": "2026-09-11T10:12:44.108Z",
  "sections": [
    {
      "sectionId": "5a2c7e90-3b16-4d82-9f4a-8c0e5b7d1a63",
      "sectionTitle": "Truthful claims",
      "rules": "Claims must be accurate, current and substantiated.",
      "alwaysApplicable": true
    }
  ]
}

PATCH /v1/frameworks/{id}

Updates a draft framework only.

Use this for a draft's name, industry, markets, description, or supplemental domains. An approved (live) framework cannot be updated; create a new version instead, which preserves evaluations against the approved version.

Parameters

iduuidrequired
Path parameter. The draft frameworkId to update.
name, industry, markets, description, supplementalDomainsmixedoptional
Optional fields to replace. Pass an empty supplementalDomains array to clear it; omit it to leave it unchanged.

Change a draft description

Only send the fields that need to change.

Request
curl -X PATCH "https://api.voxlyvision.com/api/v1/frameworks/{id}" \
  -H "X-API-Key: $VOXLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"Updated internal guidance"}'
Response
{
  "frameworkId": "1f0c2a94-6b4f-4b3d-9a2c-0f4d5e6a7b81",
  "frameworkName": "Brand safety",
  "description": "Updated internal guidance",
  "frameworkGroupId": "8d3e5f27-1a94-4c60-b8f2-7e0a1d5c9b34",
  "frameworkType": "custom",
  "markets": ["global"],
  "industry": "general",
  "status": "draft",
  "version": 1,
  "isLatest": true,
  "createdAt": "2026-09-11T09:12:44.108Z",
  "updatedAt": "2026-09-11T10:12:44.108Z",
  "sections": []
}
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).