§ API REFERENCE

11 endpoints.

Base URL https://api.staging.starladigital.com/api. Every request carries your key in an X-API-Key header. One evaluation covers a batch of assets; each asset inside it is a job— that is the API's own noun, and the paths keep it.

Frameworks are read-only: they are authored and approved in the portal, and the API reads their ids and sections back. Values that come from a fixed set are listed on the parameter that takes them, and spelled out under vocabulary.

§ 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 we fetch. 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 we download ourselves — http is refused, as are private, loopback and link-local addresses. 500 MB per file, 8192 characters per url.
modelIdstringoptional
Pins the evaluation to a specific model. Omit it and the workspace default is used.Model ids
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.staging.starladigital.com/api/v1/evaluations" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/evaluations" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/evaluations" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/evaluations" \
  -H "X-API-Key: $STARLA_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F fileUrls="https://cdn.example.com/spring/hero.png"

Pin the model and file into a folder

Every optional field together: a specific model, a destination folder, and an idempotency key so a retry cannot charge twice.

Request
curl -X POST "https://api.staging.starladigital.com/api/v1/evaluations" \
  -H "X-API-Key: $STARLA_API_KEY" \
  -F name="Spring campaign" \
  -F frameworkIds="550e8400-e29b-41d4-a716-446655440000" \
  -F files=@hero.png \
  -F modelId="claude-opus-4-8" \
  -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.staging.starladigital.com/api/v1/evaluations/{evaluationId}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/jobs/{id}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/jobs/{id}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/assets?page=1&limit=10&order=desc" \
  -H "X-API-Key: $STARLA_API_KEY"

Search by file name

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

Request
curl -X GET "https://api.staging.starladigital.com/api/v1/assets?q=spring&order=desc" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/assets?labelIds=7b2e9c04-1f83-4a55-9d61-0c8e3b5a2f47&owned=true" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/assets/{id}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/assets/{id}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/frameworks?status=live" \
  -H "X-API-Key: $STARLA_API_KEY"

This workspace's own frameworks

Custom frameworks only, authored in the portal.

Request
curl -X GET "https://api.staging.starladigital.com/api/v1/frameworks?type=custom&status=live" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/frameworks/{id}" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/uploads" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/uploads" \
  -H "X-API-Key: $STARLA_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.staging.starladigital.com/api/v1/uploads/{uploadId}/complete" \
  -H "X-API-Key: $STARLA_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 backend's own enums. If a field is documented as a string and appears here, these are the only values it takes.

Model ids

Pass one as `modelId` to pin an evaluation to a specific model. Omitting it is always safe — the evaluation uses the workspace default.

gpt-5.5-2026-04-23
GPT-5.5 · openai
gpt-5.4-2026-03-05
GPT-5.4 · openai
gpt-5.3-chat-latest
GPT-5.3 Chat · openai
gpt-5.2-2025-12-11
GPT-5.2 · openai
gpt-5.1-2025-11-13
GPT-5.1 · openai
gpt-5-2025-08-07
GPT-5 · openai
gpt-4.1-2025-04-14
GPT-4.1 · openai
gpt-4o-2024-08-06
GPT-4o · openai
claude-opus-4-8
Claude Opus 4.8 · anthropic
claude-opus-4-7
Claude Opus 4.7 · anthropic
claude-opus-4-6
Claude Opus 4.6 · anthropic
claude-sonnet-4-6
Claude Sonnet 4.6 · anthropic
claude-haiku-4-5
Claude Haiku 4.5 · anthropic
claude-fable-5
Claude Fable 5 · anthropic

These are the ids seeded into every environment. They are kept fresh by a pricing sync, so a workspace can carry ids that are not listed here — the model picker in the portal is the live answer, and there is no API-key route that lists them. Omitting modelId is always safe.

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
Maintained by us — Portman, DISCUS, ASA, TTB.
custom
Authored by this 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).