L'invio («push»): il contratto di deposito, versione 1

Pagina tecnica, per un editore che scrive il proprio plugin o il proprio codice di invio.

Questa pagina descrive ciò che un mittente invia a Eiger Vault, ciò che riceve in risposta e come si comporta in caso di errore o di interruzione. Segue i contratti pubblicati così come sono oggi sul ramo principale dei nostri depositi: il documento nativo ev-native/1 per la richiesta, il contratto di depositare v1 per ciò che risponde il vault e il formato dei diritti ev-rights/1. Questi contratti sono versionati e una versione pubblicata non viene mai modificata: un'aggiunta arriva con una nuova versione, che non toglie nulla alla precedente. Alcuni punti saranno precisati più avanti: vedi la sezione 11.

Stato di apertura. L'interfaccia che riceve le vostre richieste non è ancora aperta su Internet; lo sarà solo all'arrivo del primo editore. Il suo indirizzo sarà comunicato in quel momento. Gli esempi qui sotto usano https://<indirizzo dell'interfaccia nativa>.

1. Il principio

Non chiamate direttamente il vault: chiamate l'interfaccia nativa, che traduce il vostro documento nativo in una richiesta di deposito, la trasmette al vault con la vostra chiave e vi restituisce la sua risposta così com'è. Non conserva nulla di ciò che passa attraverso di essa e non ha una coda: risponde solo dopo la risposta del vault. Se il vault è irraggiungibile, risponde 503.

Invio: il CMS dell'editore invia a Eiger Vault. Lettura: Eiger Vault legge nella fonte dell'editore.

Una richiesta di deposito porta un documento: i blocchi di testo dell'articolo e, facoltativamente, i suoi file (immagini, PDF della pagina, video).

2. L'autenticazione

La chiave dell'editore che vi abbiamo consegnato ha la forma evk_ seguito da sedici cifre esadecimali, da _, poi da altre sessantaquattro cifre esadecimali. Si presenta nell'intestazione Authorization, con lo schema Bearer, e in nessun altro luogo:

Authorization: Bearer evk_0123456789abcdef_<64 cifre esadecimali>

3. La richiesta

POST /deposits
Authorization: Bearer evk_0123456789abcdef_<64 cifre esadecimali>
Content-Type: multipart/form-data; boundary=…
X-Correlation-ID: <facoltativo>

POST /deposits per depositare e POST /presence-checks per la verifica collettiva (sezione 9): sono le uniche due rotte. Qualsiasi altro percorso, o qualsiasi altro metodo, riceve 404 (not-found).

Il corpo è suddiviso in più parti (multipart/form-data):

Parte Contenuto
native_document il documento nativo, in JSON obbligatoria
supplementary_metadata il descrittivo complementare, oggetto JSON libero (parole chiave del CMS, titoli alternativi) facoltativa
una parte per file i byte del file, così come sono; il suo nome è quello che il documento nativo gli assegna tante quanti sono i file

I nomi native_document e supplementary_metadata sono riservati: nessun file li assume. Ogni parte che la richiesta porta deve essere designata dal documento nativo, e ogni parte che esso designa deve essere presente. Una parte che dichiara un Content-Transfer-Encoding diverso da 7bit, 8bit o binary è rifiutata.

L'identificativo di correlazione. Potete inviare X-Correlation-ID; altrimenti l'interfaccia ne ricava uno. Accompagna la richiesta fino al vault, ritorna nell'intestazione della risposta e nel corpo di ogni rifiuto: conservatelo per qualsiasi richiesta di assistenza.

I limiti (valori iniziali, adeguati da Eiger Vault prima della messa in servizio):

Che cosa è limitato Limite
l'intera richiesta 16 MiB
la parte native_document 1 MiB
ciascuna delle altre parti 16 MiB
la parte supplementary_metadata 64 KiB

Oltre un limite, l'interfaccia smette di leggere e rifiuta con native.request-too-large (413). Con questi valori, il deposito più pesante che ne possa risultare, base64 compreso, resta sotto i 24 MiB che il vault accetta per il corpo di un deposito.

4. Il documento nativo

È un testo JSON che l'interfaccia non riscrive mai. Se non c'è un involucro d'origine esplicito, questi stessi byte sono sigillati come involucro d'origine del deposito: sono conservati così come sono.

{
  "format": "ev-native/1",
  "source": "ch-src-0192f3a4-5b6c-7d8e-9fa0-b1c2d3e4f5a6",
  "metadata": {
    "document_type": "article",
    "source_reference": "12345",
    "published_at": "2026-10-05T08:30:00+02:00",
    "title": "Un titolo",
    "authors": ["Anne Exemple"]
  },
  "body_form": "blocks",
  "text_blocks": [
    {"role": "paragraph", "text": "Un paragrafo."},
    {"role": "caption", "text": "La foto.", "file": "photo-1"}
  ],
  "files": [
    {"name": "photo-1", "role": "image", "media_type": "image/jpeg"}
  ],
  "cms_revision": "48213"
}

Il contratto è chiuso a ogni livello. Un membro che il contratto non nomina, a qualsiasi profondità, fa rifiutare il documento (native.unknown-member): un membro scritto male che passasse in silenzio verrebbe sigillato per sempre senza aver detto nulla a nessuno.

I membri del primo livello.

Membro Valore
format ev-native/1 obbligatorio
source identificativo della vostra fonte, <regione>-src-<UUID versione 7>, che vi comunichiamo obbligatorio
collection identificativo di raccolta, <fonte>:c<numero>; senza di esso, la raccolta predefinita della fonte (o quella dell'ultima versione, per un documento noto) facoltativo
metadata il descrittivo, vedi più avanti obbligatorio
body_form blocks, unica forma servita nella v1 obbligatorio
text_blocks elenco di almeno un blocco obbligatorio
files elenco di file; assente o vuoto per un articolo senza file facoltativo
rights i diritti nel formato ev-rights/1 (vedi sezione 11) facoltativo
cms_revision l'identificativo della revisione dell'articolo nel vostro CMS; stringa non vuota obbligatorio

Il descrittivo metadata.

Membro Valore
document_type article (unico tipo nella v1) obbligatorio
source_reference l'identificativo che il vostro CMS assegna all'articolo, così com'è, secondo la regola di riferimento concordata per la vostra fonte (per esempio un prefisso se la vostra fonte riunisce più edizioni) obbligatorio
version_label etichetta di versione scelta da voi; mai la revisione del CMS facoltativo
published_at, updated_at data di pubblicazione e data di aggiornamento visualizzata al lettore, vedi più avanti facoltativo
canonical_url indirizzo canonico facoltativo
language etichetta BCP 47 facoltativo
title, lede titolo, occhiello facoltativo
genres codici di genere IPTC (Analysis, Interview…); un valore sconosciuto passa e viene contato facoltativo
category percorso di categoria, elenco ordinato di etichette facoltativo
authors, places elenchi di stringhe facoltativo
relations collegamenti ad altri documenti: tipi derived_from, corrects, translates, cites; destinazione: un documento Eiger Vault, una coppia (fonte, riferimento), un indirizzo o un'impronta facoltativo

I campi che il vault scrive da sé – il tipo di schema, la sua versione, la raccolta risolta – non si dichiarano: dichiararli fa rifiutare il documento.

I blocchi. Ogni blocco ha un role – paragraph, subheading (sottotitolo), sidebar (riquadro) o caption (didascalia) – e un text non vuoto. Un riquadro porta un elenco text_blocks di almeno un blocco, che non contiene un riquadro. Una didascalia può designare un file tramite il suo name in file. Il testo è copiato senza alcuna modifica, tag compresi: il vault non vi legge alcun markup, e <b> vi conta per quattro caratteri.

I file. Ogni voce di files ha un name (univoco, non riservato: è il nome della parte che porta i byte), un role (image, video o page_pdf; mai text) e un media_type (della forma tipo/sottotipo, in minuscolo, senza parametri). I file sono conservati nell'ordine dell'elenco, byte per byte. Il nome di un file non passa mai al vault e non compare in nessuna traccia.

Le date. published_at e updated_at si scrivono o come istante RFC 3339 con il suo scarto orario, copiato così come lo tiene il CMS (2026-10-05T08:30:00+02:00), o come giorno AAAA-MM-GG, solo quando non si conosce altro. Una data senza scarto orario non è un istante. Non convertite lo scarto: lo converte il vault in UTC. updated_at è la data di aggiornamento visualizzata al lettore: se il vostro sito non ne mostra una, omettete il membro e non inseritevi mai una data tecnica di modifica. Una data assente resta assente; non la completiamo mai.

La lettura del JSON. La parte JSON è I-JSON rigoroso (RFC 7493): UTF-8 valido, senza byte order mark, senza membri ripetuti, senza surrogati isolati né non-caratteri, con soli numeri interi. Una stringa vuota, null, un elenco vuoto e un oggetto vuoto valgono «assente»: il membro è omesso, e un membro obbligatorio vuoto vale assente. Nessun blocco di text_blocks e nessun file di files viene tolto da questa regola.

Il riferimento alla fonte. È l'identificativo che il vostro CMS assegna all'articolo, senza alcuna normalizzazione, e non cambia mai per uno stesso articolo. Non si ricava da un indirizzo. Segue la forma attesa che abbiamo concordato per la vostra fonte: se non la segue, il documento è rifiutato (native.reference-rule-mismatch) senza che il rifiuto citi il riferimento.

La revisione del CMS. Identifica, per il vostro CMS, uno stato dell'articolo. Non diventa mai l'etichetta di versione. Serve a calcolare la chiave di idempotenza (sezione 6): occorre dunque che una stessa revisione produca sempre lo stesso contenuto e che una modifica visibile produca una nuova revisione.

5. La risposta

Un deposito che crea un documento o una versione risponde 201. Un deposito che non crea nulla – ripetizione riconosciuta, contenuto invariato – risponde 200, con il sigillo della versione riconosciuta. Le due risposte hanno la stessa forma:

{
  "document": "ch-0192f3a4-5b6c-7d8e-9fa0-b1c2d3e4f5a6",
  "notices": [],
  "seal": {
    "depositor": "ch-dep-0192f3a4-5b6c-7d8e-9fa0-b1c2d3e4f5a7",
    "format": "ev-seal/1",
    "identity_level": "authenticated",
    "manifest_digest": {"sha-256": "…", "sha3-512": "…"},
    "origin_proofs_digest": {"sha-256": "…", "sha3-512": "…"},
    "received_at": "2026-10-05T06:31:12.123456Z"
  },
  "version_number": 1
}
Membro Valore
document l'identificativo del documento, <regione>-<UUID versione 7>: non deriva né dal contenuto né dal vostro riferimento e non viene mai riutilizzato
version_number il numero di versione, a partire da 1
seal il sigillo di versione completo; i suoi byte sono i byte sigillati. Non porta né firma né indirizzo
notices le segnalazioni, elenco vuoto quando non ce n'è nessuna

Il sigillo restituito è copiato byte per byte da ciò che il vault ha scritto; potete conservarlo come ricevuta.

Le segnalazioni (al massimo una volta ciascuna, senza mai citare ciò che le ha causate):

Valore Significato
retry_recognized il deposito è la ripresa di un deposito già ricevuto: non è stato creato nulla
content_unchanged il contenuto è quello dell'ultima versione: non è stato creato nulla
version_label_already_used è stata creata una versione con un'etichetta già impiegata
out_of_schema_field_ignored un campo del descrittivo non appartiene allo schema ed è stato ignorato
supplementary_metadata_not_kept il descrittivo complementare è stato accettato, ma per ora non è stato trasmesso a nessuno

6. L'idempotenza

Non inviate una chiave di idempotenza: la calcola l'interfaccia, tramite un'impronta con chiave (HMAC-SHA-256, sotto la vostra chiave) della tripla (fonte, riferimento alla fonte, revisione del CMS). La chiave non è quindi mai leggibile, e una ripetizione che attraversa un rilascio da parte nostra presenta la stessa chiave. Il vault la conserva per 30 giorni, solo per il vostro depositante.

Il vostro invio Risultato
stesso documento, stessa revisione, stesso contenuto: una ripresa 200, il sigillo del primo deposito, retry_recognized
stesso documento, stessa revisione, contenuto diverso rifiuto deposit.idempotency-key-conflict (409): una stessa revisione non può portare due contenuti
stesso documento, nuova revisione, contenuto identico all'ultima versione 200, content_unchanged; nessuna nuova versione
stesso documento, contenuto cambiato 201, versione successiva
stesso documento, etichetta già impiegata, contenuto cambiato 201, versione successiva, con version_label_already_used

Primo invio, ripresa, contenuto invariato, contenuto modificato.

Trascorsi i 30 giorni, una chiave è considerata nuova. Un contenuto identico a quello dell'ultima versione restituisce allora content_unchanged anziché retry_recognized: in ogni caso non c'è una versione in più.

7. Le versioni

Un documento è identificato dalla coppia (fonte, riferimento alla fonte). Un deposito la cui coppia è nota si rivolge al documento esistente. Le versioni sono numerate 1, 2, 3, senza buchi, per documento.

Che cosa fa una versione. Si confronta il contenuto che dichiarate – il descrittivo e i componenti, testo strutturato compreso – con quello dell'ultima versione. I byte dell'involucro d'origine non entrano nel confronto. Se differiscono, questo da solo non crea una versione: una pagina rigenerata, o un documento nativo di cui cambia un membro non tradotto, non ne crea una. L'etichetta di versione e la raccolta entrano nel descrittivo: cambiarle crea una versione.

Che cosa non cambia mai. Il tipo di un documento: un deposito che lo cambiasse è rifiutato (deposit.document-type-change, 409). Il depositante che può depositare una nuova versione è qualsiasi depositante autorizzato per la fonte del documento.

La riclassificazione. Una nuova versione può cambiare raccolta all'interno della fonte del documento, designando la nuova raccolta.

La data di pubblicazione del documento è quella dichiarata dalla sua prima versione.

8. I ritiri

Non esiste alcuna operazione di ritiro nel contratto di deposito: né una cancellazione, né uno stato «non più pubblicato». Un articolo cancellato o ritirato dalla pubblicazione nel vostro CMS resta nel nostro registro, con tutte le sue versioni. Per ritirare un contenuto, l'editore ne fa richiesta a Eiger Vault; un operatore prende allora una decisione, che è iscritta nel registro per sempre con i suoi autori, il suo istante e la sua motivazione. Esistono due gradi: il blocco (il contenuto non è più mostrato a nessuno, il sigillo è conservato; la decisione è reversibile) e la cancellazione (le chiavi di cifratura dei componenti e del descrittivo sono distrutte; non si può annullare). Questa procedura sarà dettagliata prima della messa in servizio.

Ciò che non viene mai ritirato, nemmeno dopo una cancellazione: l'identificativo, le impronte, il sigillo e una lapide che dice che c'è stato un documento, quando, da parte di chi e perché non c'è più.

9. La ripresa dopo un'interruzione

Se non avete ricevuto risposta – timeout, connessione interrotta, 503 –, l'esito del deposito è sconosciuto. Reinviate la stessa richiesta, con la stessa revisione del CMS: riceverete il sigillo del primo deposito (200, retry_recognized) se è avvenuto, oppure il deposito avverrà (201). Una ripetizione non crea mai una versione doppia.

Ripresa dopo un'interruzione: reinviare la stessa richiesta, oppure verifica collettiva.

Se una serie di depositi può essere andata persa, per esempio dopo un guasto presso di voi o presso di noi, la verifica collettiva vi dice che cosa conosciamo, senza inviarci nulla:

POST /presence-checks
Authorization: Bearer evk_0123456789abcdef_<64 cifre esadecimali>
Content-Type: application/json

{"references": [{"source": "ch-src-0192f3a4-5b6c-7d8e-9fa0-b1c2d3e4f5a6", "source_reference": "12345"},
                {"source": "ch-src-0192f3a4-5b6c-7d8e-9fa0-b1c2d3e4f5a6", "source_reference": "12346"}]}

Il corpo è limitato a 1000 riferimenti e a 4 MiB. La risposta 200 dà un risultato per ogni coppia sottoposta, nell'ordine di sottomissione:

{"results": [
  {"source": "ch-src-…", "source_reference": "12345", "state": "served",
   "collection": "ch-src-…:c1", "version_label": "edizione serale",
   "comparison_digest": {"sha-256": "…", "sha3-512": "…"}},
  {"source": "ch-src-…", "source_reference": "12346", "state": "absent"}
]}
Stato Significato
absent la coppia è sconosciuta: inviate il documento
served il documento ha una versione: è già presso di noi
out_of_scope la vostra chiave non è autorizzata per questa fonte, oppure la fonte è sconosciuta; gli altri riferimenti non vengono toccati

La risposta non porta mai contenuto, né identificativo di documento, né numero di versione. Un nuovo deposito periodico consiste nell'elencare i vostri contenuti recenti (all'inizio le ultime 48 ore, ogni ora), sottoporli alla verifica collettiva, poi depositare solo i mancanti.

La modalità di nuovo deposito esiste nel contratto di deposito: un deposito così contrassegnato non crea mai una versione di un documento esistente e restituisce il sigillo della sua ultima versione. Il suo uso da parte dell'interfaccia nativa sarà precisato: vedi la sezione 11.

10. I rifiuti

Un rifiuto ha sempre la stessa forma, con il suo stato HTTP:

{"code": "native.missing-required-field", "message": "<frase fissa>", "correlation_id": "…"}

Il messaggio è una frase fissa che dice dove (il nome di un membro, la posizione di un blocco o di un file) e che cosa; non cita mai l'input: né valore, né nome di membro sconosciuto, né riferimento, né nome di file. Il codice è l'unica cosa su cui il vostro programma deve basarsi. Un rifiuto non scrive nulla presso di noi.

10.1 L'ordine

Uno stesso invio dà sempre lo stesso rifiuto, perché i controlli avvengono in un ordine fisso e la prima irregolarità dà il rifiuto. Ci sono due fasi: l'interfaccia nativa, che controlla prima di qualsiasi chiamata al vault, poi il vault.

I controlli dell'interfaccia nativa, poi quelli del vault.

Fase 1, l'interfaccia nativa.

  1. prima di leggere il documento: una stringa a forma di chiave nell'indirizzo, poi la dimensione, poi la codifica di trasferimento delle parti;
  2. la lettura I-JSON, poi la forma a oggetto del documento;
  3. format: assente o diverso da ev-native/1;
  4. i nomi dei membri, a ogni livello;
  5. i membri, nell'ordine source, collection, metadata, body_form, text_blocks, files, rights, ciascuno in profondità;
  6. l'involucro d'origine esplicito e le sue prove, se presenti;
  7. le designazioni: ogni nome di file, poi ogni didascalia;
  8. cms_revision;
  9. il confronto delle parti della richiesta con ciò che il documento designa; poi la fonte nella configurazione dell'interfaccia e il riferimento rispetto alla regola della sua fonte.

La collocazione esatta del confronto delle parti della richiesta rispetto ai passi da 3 a 8 sarà precisata.

Fase 2, il vault, secondo il contratto di depositare v1:

  1. la chiave;
  2. l'attribuzione a una fonte o a una raccolta e il perimetro: fonte o raccolta non autorizzata, disattivata, sconosciuta, non designata e, solo nel nostro ambiente di prova, fonte non ammessa;
  3. la dimensione del corpo e di ogni componente;
  4. il formato della richiesta, del descrittivo, dei componenti e del testo strutturato;
  5. le prove d'origine, se ce ne sono;
  6. un involucro d'origine già legato a un altro documento;
  7. sotto il blocco del documento, nell'ordine: il perimetro è riletto; poi la decisione della sezione 7: una chiave di idempotenza già vista, un cambio di tipo, il riconoscimento di una ripetizione, di un contenuto invariato, oppure la creazione di una versione.

Un membro di primo livello che il contratto di deposito non conosce, o un corpo che non è un oggetto, è rifiutato con deposit.malformed-request.

10.2 I codici dell'interfaccia nativa

Causa Codice Stato
la parte JSON non è I-JSON rigoroso native.invalid-json 400
versione di formato assente o non servita native.unsupported-format 400
membro che il contratto non nomina native.unknown-member 400
membro obbligatorio assente native.missing-required-field 400
forma del corpo non servita native.unsupported-body-form 400
altra irregolarità: forma di un valore, ruolo fuori vocabolario, file di ruolo text o original, data o tipo di media scritti male, nome di file duplicato o riservato, didascalia verso un file assente dall'elenco native.invalid-native-document 400
involucro d'origine esplicito senza prova, o prova senza involucro native.unpaired-original-envelope 400
il documento designa una parte assente dalla richiesta native.missing-form-part 400
la richiesta porta una parte che il documento non designa, o due parti con lo stesso nome native.undesignated-form-part 400
codifica di trasferimento di una parte diversa da 7bit, 8bit, binary native.unsupported-transfer-encoding 400
una stringa a forma di chiave nell'indirizzo, nella parte JSON o nel corpo native.key-outside-header 400
una parte, la richiesta o il corpo di una verifica collettiva supera il proprio limite native.request-too-large 413
descrittivo complementare che non è un oggetto I-JSON, o troppo grande native.invalid-supplementary-metadata 400
il riferimento non segue la forma attesa della sua fonte native.reference-rule-mismatch 400
la fonte designata non è configurata nell'interfaccia native.unconfigured-source 403
altro percorso o altro metodo not-found 404
vault irraggiungibile, o sua risposta illeggibile unavailable 503

Una chiave scritta con sequenze di escape \u nella parte JSON si scopre solo alla lettura di quest'ultima: native.invalid-json precede allora native.key-outside-header.

10.3 I codici del vault, restituiti così come sono

Causa Codice Stato
chiave sconosciuta, revocata, assente, malformata, o di un depositante disattivato deposit.unknown-or-revoked-key 401
richiesta malformata: membro sconosciuto, corpo che non è un oggetto… deposit.malformed-request 400
fonte designata sconosciuta o non autorizzata, autorizzazione ritirata, o depositante autorizzato per nessuna fonte deposit.source-not-authorized 403
la fonte è disattivata deposit.source-deactivated 403
la raccolta è disattivata deposit.collection-deactivated 403
(ambiente di prova) fonte non ammessa deposit.source-not-staging-admitted 403
raccolta sconosciuta, o che non è quella della fonte designata deposit.unknown-collection 404
più fonti autorizzate, e nessuna designata deposit.source-not-designated 400
componente o corpo troppo voluminoso (componente > 16 MiB, corpo > 24 MiB) deposit.part-or-body-too-large 413
involucro d'origine già legato a un altro documento deposit.original-envelope-of-another-document 409
chiave di idempotenza vista, con un altro contenuto o per un altro documento deposit.idempotency-key-conflict 409
cambio di tipo di un documento deposit.document-type-change 409
rifiuto del formato: JSON non conforme, numero, data, impronta, componente o riferimento mancante, tipo di media, testo strutturato, descrittivo, componente, testo, prova d'origine format.invalid-json, format.invalid-number, format.malformed-date, format.malformed-digest, format.missing-required-field, format.malformed-media-type, format.invalid-structured-text, format.invalid-text-part, format.invalid-metadata, format.invalid-part, format.incomplete-digest-only, format.unsupported-origin-proof-type, format.invalid-origin-proof 400
chiavi del vault non ancora sbloccate, o compartimento dei componenti che non risponde unavailable 503

I codici propri di una lettura (deposit.attested-fetch-missing, deposit.invalid-attested-fetch, deposit.domain-outside-source-domains, deposit.original-envelope-not-attested) non riguardano un invio con chiave dell'editore. Se un codice indichi un rifiuto definitivo o transitorio si legge dal suo stato: ogni 4xx è definitivo finché la richiesta non cambia; un 503 si riprova, con la stessa richiesta.

11. Che cosa sarà chiarito

Alcuni punti del contratto saranno precisati o completati. Ve li annunceremo, e un'aggiunta non cambierà ciò che questa pagina già descrive.

12. I vettori

Il contratto del documento nativo è fornito con vettori di riferimento: documenti nativi ammessi, con la richiesta di deposito che producono, e documenti rifiutati, con il loro codice. Non cambiano mai e possono essere riprodotti contro il vostro codice. Ve li consegniamo insieme al contratto.