Marca un’immagine, un brano o una clip
POST https://api.kennmarq.com/v1/mark
Invia un’immagine o un brano e ti torna indietro con una filigrana invisibile e un manifest C2PA firmato e con marca temporale. Invia una clip e ricevi un job, poi la clip marcata da GET /v1/marks/{id} quando è pronta. Un’immagine conta una marcatura, un brano cinque per ogni minuto iniziato, una clip cinque per ogni secondo iniziato. Serve una chiave con l’ambito mark.
Richiesta
multipart/form-data, con questi campi. Ai campi di testo vengono tolti gli spazi iniziali e finali; i flag accettano true/false (oppure 1/0, on/off, yes/no).
| Campo | Tipo | Descrizione |
|---|---|---|
file | file, obbligatorio (oppure upload) | Il file: un’immagine PNG, JPEG o WebP; un brano MP3, WAV o M4A; oppure una clip MP4. Il tipo viene ricavato dai suoi byte, non dal nome. L’intera richiesta è al massimo di 4 MB; un file più grande passa da un upload, indicato in upload: fino a 25 MB, e una clip fino a 1 GB. |
upload | testo, al posto di file | L’ID di un upload (up_…) da POST /v1/uploads, per un file oltre i 4 MB. Funziona una sola volta, entro un’ora, con la chiave che lo ha creato. |
source | testo, predefinito created | Come è stata creata l’immagine, registrato come suo digital source type IPTC: created (creata dall’IA), composite (IA combinata con altro materiale) o edited (un’immagine esistente modificata con l’IA). Lo dichiari tu; firmiamo solo tipi di origine IA. |
provider | testo, facoltativo | La tua denominazione legale, in quanto fornitore del sistema di IA, ad es. Acme Inc. Con app_name e app_version completa la dichiarazione latente della California. Al massimo 200 caratteri. |
model | testo, facoltativo | Il nome del modello, ad es. FLUX.1 schnell. Al massimo 200 caratteri. |
model_version | testo, facoltativo | La versione del modello. Al massimo 200 caratteri. |
app_name | testo, facoltativo | Il nome del tuo sistema di IA, registrato come agente software dell’azione created. Senza di esso, il manifest non indica alcun agente software. Al massimo 200 caratteri. |
app_version | testo, facoltativo | La versione del tuo sistema di IA. Richiede app_name. Al massimo 200 caratteri. |
markets | testo, facoltativo | I mercati per cui viene fatta la marcatura, separati da virgole: il codice ISO di qualsiasi paese (de, jp), eu, uno Stato USA (us-ca) o us per tutti gli Stati con una legge propria. Ogni file riceve ciò che chiedono le leggi di quei paesi (la mappa mondiale le mostra), una chiamata priva di quanto richiedono viene rifiutata (us-ca e us-wa richiedono provider, app_name e app_version; in richiede app_name), e la marcatura riceve una ricevuta firmata. in applica l’etichetta visibile a ogni immagine e clip. Un mercato le cui norme richiedono ciò che non aggiungiamo ancora viene rifiutato con option_not_available: la Cina, i deepfake del Vietnam, i brani dell’India e i deepfake nei brani per eu e kr. |
deepfake | flag, predefinito false | Il file è un deepfake: assomiglia a persone, luoghi o eventi reali e potrebbe sembrare autentico (art. 50, par. 4, dell’AI Act). Attiva l’etichetta visibile; con eu o kr in markets non si può disattivare. Non ancora disponibile per i brani. |
label | flag | Immagini e clip: disegna nel file l’etichetta IA visibile dell’UE, prima della filigrana. Disattivata per impostazione predefinita; attiva per i deepfake e per in. |
label_language | testo, predefinito en | La parola accanto ad «AI»: en (AI GENERATED), ko (AI 생성) o zh (AI生成). ko per impostazione predefinita con kr in markets. |
label_position | testo, predefinito top-right | top-right, top-left, bottom-right o bottom-left, dove la vede chi guarda (si tiene conto della rotazione EXIF di una foto). |
label_size | testo, predefinito medium | small, medium o large: il 5, il 7 o il 10% del lato più corto, almeno 20 pixel. in richiede medium o large. |
label_style | testo, predefinito auto | auto (nera su un angolo chiaro, bianca su uno scuro), dark, light, dark-translucent o light-translucent: le quattro varianti del Codice. |
title | testo, facoltativo | Un titolo per il file. Al massimo 200 caratteri. |
watermark | flag, predefinito true | Aggiunge la filigrana invisibile. Disattivala solo se il file contiene già la nostra, ad es. perché applicata in locale. |
iptc | flag, predefinito true | Immagini: scrive l’IPTC DigitalSourceType nei metadati XMP del file. Brani e clip lo indicano nel loro manifest. |
output_format | testo, predefinito keep | Un’immagine: keep, png, jpeg o webp. Un brano: keep, mp3, wav o m4a. Una clip: keep o mp4 (sempre H.264 in MP4). |
keep_input_credentials | flag, predefinito true | Conserva come ingrediente le Content Credentials che il file contiene già (ad esempio dall’API di un modello a monte), come chiede la misura 1.2 del codice di buone pratiche. |
input | file, facoltativo | Per gli strumenti di modifica: l’immagine di input dell’utente (oppure, per un brano o una clip, un brano di input). Se contiene Content Credentials, vengono conservate come ingrediente; nient’altro viene registrato. Un’immagine di input passa per la nostra soglia minima e, con check attivo, per la tua policy. |
input_upload | testo, al posto di input | L’ID dell’upload dell’input, per un input oltre i 4 MB (o per file e input che insieme superano i 4 MB). |
check | testo, predefinito off | Il controllo di sicurezza prima della marcatura: ai-act, safe-only o off. In caso di blocco non viene marcato nulla e ricevi 422 content_blocked con il motivo. Ogni immagine controllata conta due marcature; una clip viene controllata su 12 fotogrammi, due marcature ciascuno. Un brano non ha immagini: lascialo disattivato. |
Le opzioni in programma (metadata, webhook, ai_disclosure, categorize, describe, la marcatura da url) vengono rifiutate con 400 option_not_available invece di essere ignorate, così un file non sembra mai contenere qualcosa che non contiene.
Esempio
curl https://api.kennmarq.com/v1/mark \
-H "Authorization: Bearer $KENNMARQ_API_KEY" \
-F file=@render.jpg \
-F source=created \
-F provider="Acme Inc." \
-F model="FLUX.1 schnell" \
-F model_version="1.0" \
-F app_name="Acme Studio" \
-F app_version="2.1" \
-F output_format=webp \
-D headers.txt \
-o render.marked.webpimport { readFile, writeFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("render.png")], { type: "image/png" }), "render.png");
form.append("source", "created");
form.append("model", "FLUX.1 schnell");
const res = await fetch("https://api.kennmarq.com/v1/mark", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.KENNMARQ_API_KEY}` },
body: form,
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("render.marked.png", Buffer.from(await res.arrayBuffer()));
console.log(res.headers.get("x-mark-id"), res.headers.get("x-marks-used"));import os, requests
with open("render.png", "rb") as f:
res = requests.post(
"https://api.kennmarq.com/v1/mark",
headers={"Authorization": f"Bearer {os.environ['KENNMARQ_API_KEY']}"},
files={"file": ("render.png", f, "image/png")},
data={"source": "created", "model": "FLUX.1 schnell"},
timeout=60,
)
res.raise_for_status()
open("render.marked.png", "wb").write(res.content)
print(res.headers["X-Mark-Id"], res.headers["X-Marks-Used"])Risposta
200 con il file marcato come body, e questi header:
| Header | Valore |
|---|---|
Content-Type | Il tipo del file marcato: image/png, image/jpeg, image/webp, audio/mpeg, audio/wav o audio/mp4. |
Content-Disposition | attachment, con il nome del file più .marked e l’estensione corretta (image.marked.png per un’immagine inviata tramite upload). |
X-Mark-Id | L’ID di questa marcatura (mk_…). Indicalo all’assistenza. |
X-Watermark-Id | L’ID contenuto nella filigrana (esadecimale). Assente con watermark=false. |
X-Log-Index | La posizione della firma di questo file nel nostro registro di trasparenza pubblico: GET /v1/log/proof/{index} prova che è lì. |
X-Marks-Used | Le marcature usate questo mese nell’ambiente di questa chiave, compresa questa. |
X-Marks-Limit | La quota del mese per l’ambiente di questa chiave. |
X-Marks-Counted | Brani: le marcature conteggiate per questo brano, cinque per ogni minuto iniziato. |
X-Audio-Watermark | Brani: claimed (la marcatura si rilegge dal file e il manifest lo dichiara), unclaimed (troppo silenzioso per rileggerla: il file è comunque firmato) o off. |
X-Safety-Verdict, X-Safety-Reason | Con check attivo: allow o flag, e il motivo di una segnalazione (sexual_realistic_face: ottieni il consenso della persona). |
X-Request-Id | L’ID di questa richiesta (req_…), presente anche in ogni body di errore. |
X-RateLimit-Limit, -Remaining, -Reset | Vedi i limiti di frequenza; Reset è un orario Unix in secondi. |
Etichette visibili
Con label attivo, disegniamo nell’immagine, o in ogni fotogramma della clip, l’icona dell’UE del codice di buone pratiche sui contenuti generati dall’IA: «AI» in maiuscolo, e GENERATED per created o MODIFIED per composite ed edited, come mostra il suo allegato 1. Viene applicata prima della filigrana, quindi filigrana e firma la coprono, e il manifest la registra (un’azione c2pa.edited e un’asserzione com.kennmarq.label): il verificatore e /v1/verify la mostrano.
Per impostazione predefinita si trova nell’angolo in alto a destra, dove la colloca l’esempio del Codice, con una dimensione calcolata sul lato più corto, e in ogni fotogramma di una clip, come raccomanda il Codice. auto sceglie il nero o il bianco in base ai pixel sottostanti, così resta leggibile su qualsiasi sfondo. Un’immagine troppo stretta per l’etichetta a pillola riceve l’icona rotonda «AI».
deepfake=true la attiva, e i mercati decidono quando deve restare attiva: l’India sempre, l’UE e la Corea del Sud per i deepfake. La ricevuta la riporta per ogni mercato.
curl https://api.kennmarq.com/v1/mark \
-H "Authorization: Bearer $KENNMARQ_API_KEY" \
-F file=@portrait.jpg \
-F source=edited \
-F app_name="Acme Studio" \
-F markets=eu,in \
-F deepfake=true \
-o portrait.marked.jpgLa stessa etichetta nella tua interfaccia
Accanto a un file, in un feed o dove un’immagine non può contenerla, mostra la stessa etichetta con il nostro web component: un solo script, nessuna richiesta, nessun cookie, e gli screen reader la leggono come «AI-generated content». Il Codice chiede proprio questo tipo di indicazione accanto alle opere artistiche, e la Corea del Sud per i contenuti mostrati all’interno del tuo servizio.
<script src="https://kennmarq.com/label.js" defer></script>
<kennmarq-label kind="generated" lang="en" theme="dark" size="24"></kennmarq-label>kind: generated o modified. lang: en, ko o zh. theme: dark, light, dark-translucent o light-translucent. size: l’altezza in pixel. href la trasforma in un link, ad esempio alla pagina in cui si può verificare il file. È sotto licenza MIT: copialo nella tua app se preferisci non caricarlo da noi.
Brani
MP3, WAV o M4A, fino a 15 minuti. Il brano torna nella stessa chiamata, nel suo formato (o in quello indicato da output_format), con la sua frequenza di campionamento, i suoi canali e i suoi tag di testo; la copertina non viene conservata. Il suo suono contiene la marcatura AudioSeal di Meta, modellata sotto la musica in modo che nessuno la senta, e il suo manifest è firmato e con marca temporale come quello di un’immagine. I 16 bit di AudioSeal dicono che il file è stato marcato da noi, non quale file sia: la credenziale di provenienza di un brano viaggia nel suo manifest, e un brano non ha X-Watermark-Id.
La marcatura viene riletta dal file codificato: se si rilegge, il manifest dichiara che il file la contiene (X-Audio-Watermark: claimed). In una registrazione molto silenziosa o muta non c’è nulla sotto cui nasconderla; il file viene allora firmato senza quella dichiarazione (unclaimed). Un brano più lungo delle marcature che ti restano questo mese viene rifiutato prima di qualsiasi elaborazione, con 402 quota_exceeded.
Clip
MP4 (o QuickTime), fino a 4.500 fotogrammi (2,5 minuti a 30 fotogrammi al secondo, 75 secondi a 60, 5 minuti a 15), 1920x1080 in orizzontale o in verticale, 60 fotogrammi al secondo, 1 GB tramite un upload: ciò che riusciamo a marcare entro il tempo di un job. Il tuo piano marca alcune clip in contemporanea (clip in contemporanea). Una clip viene marcata come job: la chiamata risponde subito 202 con l’ID della marcatura, e GET /v1/marks/{id} indica quando è pronta, con un link per scaricarla. Gli endpoint che aggiungi nella dashboard ricevono mark.completed o mark.failed (webhook).
{ "object": "mark", "id": "mk_…", "status": "running", "kind": "clip",
"created_at": "2026-11-12T10:00:00.000Z", "url": "https://api.kennmarq.com/v1/marks/mk_…" }Ogni fotogramma contiene la filigrana Video Seal di Meta, con un ID casuale come quello di un’immagine (watermark_id): rimanda alla credenziale di provenienza durevole della clip quando i suoi metadati vengono rimossi. Il suo suono contiene AudioSeal, come un brano. La clip torna in H.264 in MP4, dritta (la rotazione di un telefono viene applicata ai pixel), con le stesse dimensioni, gli stessi tempi dei fotogrammi e lo stesso suono, firmata e con marca temporale. Prima dell’invio, l’ID della filigrana viene riletto da 64 dei suoi fotogrammi; una clip da cui non si rilegge non va a buon fine, come un’immagine. La nostra soglia minima di sicurezza legge 12 fotogrammi di ogni clip e, con check, li valuta anche secondo la tua policy (due marcature per fotogramma); un fotogramma bloccato fa fallire il job, con la risposta per quel fotogramma in safety.
Cosa verifichiamo prima di rispondere
In caso di problemi non restituiamo nulla (fail closed): un file torna indietro solo se è stato marcato come richiesto. Prima di rispondere, il marcatore rilegge il file firmato e convalida il suo manifest e la sua marca temporale; poi verifichiamo che la risposta sia per questa marcatura, in questo ambiente, nel formato richiesto, con esattamente i byte descritti dal marcatore. Se qualcosa non torna ricevi 502 mark_failed e nessun file, e la marcatura non viene conteggiata.
Il controllo di sicurezza
Ogni immagine che marchiamo passa per la nostra soglia minima, qualunque cosa tu invii: i contenuti espliciti con qualcuno che sembra un minore non vengono mai marcati, e la chiamata risponde 422 content_blocked. Con check impostato, il file e l’input vengono controllati anche secondo la tua policy. Una clip viene letta su 12 fotogrammi. Un blocco risponde con il controllo in safety, e picture indica di quale immagine si trattava:
{
"error": { "code": "content_blocked", "message": "The safety check blocked this picture, so nothing was marked. See \"safety\" for why.", "request_id": "req_…" },
"safety": { "object": "safety_check", "policy": "ai-act", "verdict": "block", "reason": "sexual_apparent_minor",
"nudity": { "label": "explicit", "score": 0.98 }, "apparent_minor": true, "realistic_face": true,
"picture": "file", … }
}Una chiamata bloccata conta i controlli eseguiti, non la marcatura. Un blocco dovuto solo alla nostra soglia minima, con check disattivato, non conta nulla.
Errori
| Stato | Codice | Quando |
|---|---|---|
| 400 | invalid_request | Nessun file, un campo inviato due volte o un’opzione fuori intervallo. |
| 400 | unknown_field | Un campo che questo endpoint non conosce: un refuso non passa mai inosservato. |
| 400 | option_not_available | Un’opzione in programma, come metadata o webhook, oppure un mercato le cui norme richiedono ciò che non aggiungiamo ancora (Cina, Vietnam, i brani dell’India). |
| 401 | missing_api_key, invalid_api_key, api_key_revoked | Vedi la pagina Autenticazione. |
| 402 | quota_exceeded | Le marcature o la quota di dati del mese sono esaurite, oppure un brano richiede più marcature di quelle rimaste (non viene marcato nulla). |
| 403 | insufficient_scope, ip_not_allowed | La chiave non ha l’ambito mark, oppure l’indirizzo non è tra gli IP consentiti. |
| 404 | upload_not_found | L’upload indicato non è utilizzabile con questa chiave: sconosciuto, già usato, scaduto o di un’altra chiave. |
| 413 | payload_too_large | La richiesta supera i 4 MB (invia i file più grandi tramite un upload), oppure il file supera i nostri limiti: brani di 15 minuti, clip di 4.500 fotogrammi fino a 1920x1080. |
| 415 | unsupported_media_type | Non è un’immagine, un brano o una clip che accettiamo, oppure non è stato inviato come multipart/form-data. |
| 422 | content_blocked | Il controllo di sicurezza ha bloccato il file o l’input. Il campo safety del body ne indica il motivo; non è stato marcato nulla. |
| 429 | rate_limited | Troppe chiamate in questo minuto (tutte le chiavi della tua organizzazione insieme), troppe chiamate non riuscite oggi dopo che le avevamo elaborate, oppure (per una clip) sono già in corso tutte le clip in contemporanea del tuo piano, o troppe clip non sono riuscite: riprova dopo i secondi indicati da Retry-After. |
| 502 | mark_failed | Non è stato possibile marcare e verificare il file; non viene restituito alcun file. Non viene addebitato nulla. |
| 503 | marker_unavailable, storage_unavailable | Il servizio di marcatura o gli upload sono momentaneamente non disponibili. Non viene addebitato nulla; riprova. |
Il body degli errori segue il formato comune.
Privacy
Registriamo l’ID di ogni marcatura, l’ID della filigrana, lo SHA-256 e le dimensioni, mai il file, il suo nome o il suo contenuto. Il file marcato di una clip resta a tua disposizione per un giorno, poi viene eliminato. Le marcature dicono come è stato creato un file, mai chi l’ha creato né il prompt. La risposta di un controllo di sicurezza non viene mai scritta nelle marcature del file, e di un’immagine bloccata non si conserva nulla. Un upload viene eliminato non appena la chiamata lo ha usato.