Skip to content

A mark's status

GEThttps://api.kennmarq.com/v1/marks/{id}

A clip is marked as a job (POST /v1/mark answers 202 with its ID): ask here until it's done, then download the marked clip. Asking counts no marks. Needs a key with the mark scope, of the mark's organisation and environment.

Example

curl
curl https://api.kennmarq.com/v1/marks/mk_… -H "Authorization: Bearer $KENNMARQ_API_KEY"
200 application/json, done
{
  "object": "mark", "id": "mk_…", "status": "completed", "kind": "clip",
  "created_at": "2026-11-12T10:00:00.000Z", "finished_at": "2026-11-12T10:01:12.000Z",
  "file": { "type": "video/mp4", "bytes": 18734211, "sha256": "…", "seconds": 9.6, "width": 1920, "height": 1080, "frames": 230 },
  "watermark_id": "1d455a804e9802a6",
  "watermarks": { "video": { "alg": "Meta Video Seal 1.0", "id": "1d455a804e9802a6", "read_back": 1, "frames": 64, "strength": 0.2 },
                  "audio": { "alg": "Meta AudioSeal (16 bits)", "claimed": true, "detected": 0.71, "bits": 16 } },
  "manifest": "urn:c2pa:…", "log_index": 1234, "marks": 10, "safety": null,
  "download": { "url": "https://…", "expires_at": "2026-11-12T10:06:12.000Z" },
  "download_until": "2026-11-13T10:01:12.000Z", "download_links_left": 4, "download_error": null
}

While the job runs, the answer is {"object": "mark", "id": "mk_…", "status": "running", …}. Most clips take a minute or two; ask every few seconds, or let a webhook tell you. The download link needs no key: it is the permission, so share it with care. A picture or song was marked in its own call: here it is completed, with no download.

Downloads

A finished clip's file is kept for a day. Each link to it works for 5 minutes: start the download within them (a download that has started finishes). Asking again within those 5 minutes gives the same link's time; after them, a new link, up to 5 per clip. The file's size counts against your month's data once when the job finishes, which covers the first link, and again for each later link. Once the month's data is used up, no new link is made until the 1st (UTC) or a bigger plan.

Fields

Fields of a mark
FieldDescription
statusrunning, completed or failed.
kindpicture, song or clip (an MP4 holding only sound comes back as a song).
fileThe marked file: type, bytes, sha256, seconds, and a clip's width, height and frames.
watermark_idA clip's Video Seal ID (16 hex digits), the key to its durable credential; null for a song.
watermarksvideo: the ID and how much of it read back; audio: whether the sound's mark was claimed.
manifest, log_indexThe manifest's label, and where its signature sits in the transparency log.
marksThe marks it counted: five a second, and two per checked frame.
safetyWith check on: the policy and the verdict (allow or flag, with a flag's reason).
downloadurl and expires_at: a link to the marked file that works for 5 minutes (see Downloads); null when there's none, with the reason in download_error.
download_untilThe file is kept a day after the job finished.
download_links_leftHow many more links the clip can get: 5 in all.
download_errorWhy download is null: gone (past its day), download_limit (its 5 links are used), quota_exceeded (the month's data is used up), storage_unavailable (retry). Otherwise null.
errorA failed job's code and message (as an error body's), and safety for a blocked frame.

Receipts

GEThttps://api.kennmarq.com/v1/marks/{id}/receipt

A mark made with markets has a receipt: for each market, the law, what the file carries for it, anything it lacks, and what stays with you as the provider. We sign it with our checker key when you ask for it, so you can keep it as evidence; GET /v1/verify/key serves the same key. Marks made without markets, or in local mode, have none (404 not_found).

curl
curl https://api.kennmarq.com/v1/marks/mk_4Q8oT1n6mWc2fLr0aZ9eYb/receipt \
  -H "Authorization: Bearer $KENNMARQ_API_KEY"
200 OK
{
  "receipt": {
    "object": "receipt",
    "mark_id": "mk_4Q8oT1n6mWc2fLr0aZ9eYb",
    "made_at": "2026-10-24T10:00:00Z",
    "file": { "type": "image/png", "sha256": "…" },
    "marks": {
      "credential": { "manifest": "urn:c2pa:…", "time_stamp": { "serial": "…", "time": "2026-10-24T10:00:00Z" } },
      "watermark": { "alg": "com.adobe.trustmark.Q", "id": "1a2b3c4d5e6f7081" },
      "sound_watermark": null
    },
    "origin": { "provider": "Acme Inc.", "system": "Acme Studio", "system_version": "2.1", "source": "created", … },
    "markets": [
      { "market": "us-ca", "law": "California AI Transparency Act …", "applied": ["a latent disclosure: …", …], "missing": [], "yours": ["being the covered provider", …] }
    ],
    "rules_checked": "2026-10-24",
    "guarantee": "…"
  },
  "jws": "eyJhbGciOiJFUzI1NiIs…",
  "key_id": "…",
  "public_key": "-----BEGIN PUBLIC KEY-----…"
}

When a job fails

status: failed, with the error a call would have answered: content_blocked (a frame the safety check blocked, in safety, with its frame), quota_exceeded (the clip needs more marks than were left), payload_too_large (over our limits), invalid_request (a file we can't read), mark_failed or marker_unavailable. A failed job counts nothing, but a block's checks when you asked for them. After a failure on our side, the upload works again until its hour is up. Clips that fail with mark_failed after we worked on them have a daily cap (clips).

Errors of the call itself (a key without the scope, a mark of another organisation, a typo in the ID) follow the common format: 401, 403, 404 not_found, 429.