API-Referenz
Sellat API v2
Alles, was die Web-App kann, aus deinem eigenen System: den SHA-256-Fingerabdruck einer Datei registrieren, in Polygon und Bitcoin verankern, den qualifizierten Zeitstempel der FNMT anfordern, Zertifikat und Beweispaket laden und das Original verwahren. REST und JSON, mit einem API-Key.
https://sellat.app/api/v2 Einführung
Die API arbeitet mit dem Fingerabdruck der Datei, nicht mit der Datei: Du berechnest den SHA-256 bei dir und sendest nur diese 64 Zeichen. Das Original verlässt deinen Rechner nicht, außer du gibst es in Verwahrung.
Jeder Nachweis kommt in einen Merkle-Batch, der in Polygon verankert wird; derselbe Batch wird in Bitcoin bestätigt. Auf Wunsch erhält der Fingerabdruck zusätzlich den qualifizierten Zeitstempel der FNMT-RCM, eines qualifizierten Vertrauensdiensteanbieters der EU-Vertrauensliste.
Alle Routen hängen an der Basis-URL und sprechen JSON. Nachweise aus der API und aus dem Web gehören zum selben Konto und erscheinen im selben Dashboard.
Sie ist für Aufrufe vom Server gedacht: Sie sendet keine CORS-Header, ein Browser kann sie also nicht von einer anderen Website aus aufrufen, und dein Key darf nie in Code stehen, der einen Browser erreicht.
Authentifizierung
Jede Anfrage trägt deinen Key im Header Authorization: Bearer sellat_.... Keys erstellst und widerrufst du in deinem Dashboard; ein Konto kann bis zu 5 aktive Keys haben, einen je Integration.
Ohne Key oder mit einem widerrufenen antwortet die API 401 unauthorized mit dem Header WWW-Authenticate: Bearer. Die einzige öffentliche Route ist der portable Nachweis (/proof/{id}.json).
curl https://sellat.app/api/v2/account \
-H "Authorization: Bearer sellat_3f9c..." Schnellstart
Berechne den Fingerabdruck, erstelle den Nachweis mit qualifiziertem Zeitstempel und bewahre die zurückgegebene id auf. Nach wenigen Minuten ist er anchored und alle URLs funktionieren.
Ohne "qualified": true ist der Nachweis genauso überprüfbar (Polygon und Bitcoin) und verbraucht keinen Zeitstempel. Den Zeitstempel kannst du später mit POST /proofs/{id}/qualified anfordern.
# Your key, from the dashboard
export SELLAT_API_TOKEN=sellat_...
# The fingerprint: the file stays on your machine
HASH=$(sha256sum contract.pdf | cut -d' ' -f1)
# The proof, with the FNMT qualified seal
curl https://sellat.app/api/v2/proofs \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"hash\":\"$HASH\",\"name\":\"contract.pdf\",\"qualified\":true}" Status eines Nachweises
Das Feld state sagt, was Sellat im jeweiligen Moment weiß: Eine Transaktion wird nie als bestätigt gemeldet, bevor sie geprüft ist.
Die Bitcoin-Bestätigung (bitcoin) läuft getrennt: pending, bis OpenTimestamps sie in einen Block aufnimmt, dann confirmed mit Blockhöhe. Der qualifizierte Zeitstempel (qualified) hängt nicht vom Status ab: Er wird sofort ausgestellt.
| Status | Bedeutung |
|---|---|
queued | Empfangen. Wartet auf einen Batch, höchstens etwa zwei Minuten. |
batched | In einem Merkle-Batch, der Pfad steht fest. Wartet auf die Verankerung in Polygon. |
anchored | Verankert: Die Transaktion steht in einem Polygon-Block. proof.json ist verfügbar. |
confirmed | Der Block hat 12 Bestätigungen. |
Fehler
Ein Fehler ist immer JSON mit error.code (stabil, für deinen Code) und error.message (für Menschen). Manche enthalten weitere Felder, etwa seals_remaining und buy_url bei einem 402. Der portable Nachweis ist öffentlich und antwortet {"error": "..."}.
Bricht das Gateway eine Anfrage ab, bevor sie die API erreicht (zu viele Anfragen von einer IP oder ein Body über 25 MB), hat dieses 429 oder 413 nicht dieses Format.
| Code | HTTP | Was passiert ist |
|---|---|---|
invalid_request | 400 | Ein Feld fehlt oder hat nicht das erwartete Format. Die Meldung sagt, welches. |
unauthorized | 401 | Kein Key, ein fehlerhafter oder ein widerrufener Key. |
payment_required | 402 | Keine qualifizierten Zeitstempel mehr. Enthält seals_remaining und buy_url. |
key_without_account | 403 | Der Key gehört zu keinem Konto (alte Keys). |
not_found | 404 | Der Nachweis existiert nicht oder gehört einem anderen Konto. |
conflict | 409 | Ein anderes Konto hat diese Bytes zuerst registriert, oder das Original ist noch nicht gespeichert. |
hash_mismatch | 409 | Die hochgeladene Datei hat nicht den Fingerabdruck des Nachweises. |
file_too_large | 413 | Die Datei überschreitet das Limit pro Datei deines Plans (max_file_bytes). |
rate_limited | 429 | Zu viele Anfragen pro Minute. Beachte Retry-After. |
quota_exceeded | 429 | Tageslimit für Nachweise erreicht. Retry-After bis 00:00 UTC. |
download_quota_exceeded | 429 | Tageslimit für Downloads des Originals erreicht. |
integrity_failed | 500 | Das gespeicherte Original passt nicht mehr zu seinem Fingerabdruck und wird nicht ausgeliefert. |
unavailable | 502 · 503 | Ein interner Dienst antwortet nicht. Später erneut versuchen. |
seal_unavailable | 503 | Die Zeitstempelstelle ist gerade nicht erreichbar. |
custody_unavailable | 503 | Die Verwahrung ist gerade nicht verfügbar. |
custody_quota_exceeded | 507 | Kein Verwahrungsplatz mehr in deinem Konto. |
{
"error": {
"code": "payment_required",
"message": "No qualified seals left on this account.",
"seals_remaining": 0,
"buy_url": "https://sellat.app/precios"
}
} Limits
Jedes Konto kann pro Tag eine bestimmte Zahl von API-Nachweisen erstellen, über alle Keys zusammen. Nachweise aus dem Web zählen nicht, und das erneute Senden von Bytes, die dir schon gehören, auch nicht. Der Tag beginnt um 00:00 UTC neu.
Am Limit antwortet POST /proofs mit 429 quota_exceeded, einem quota-Objekt und Retry-After. Außerdem hat jede Route eine Bremse pro Minute (etwa 60 Erstellungen und 10 Zeitstempel pro Minute), die mit 429 rate_limited antwortet, und das Gateway erlaubt bis zu 120 Anfragen pro Minute und IP. Ein Body darf höchstens 25 MB groß sein.
Qualifizierte Zeitstempel haben kein Tageslimit: Jeder verbraucht einen Zeitstempel aus deinem Guthaben. Was dir bleibt, siehst du jederzeit mit GET /account; brauchst du mehr Volumen, schreib an [email protected].
| Kostenloses Konto | Pro-Konto | |
|---|---|---|
| API-Nachweise pro Tag | 10 | 5.000 |
| Aktive Keys | 5 | 5 |
| Original in Verwahrung, pro Datei | 10 MB | 50 MB |
| Verwahrung insgesamt | 50 MB | 5 GB |
| Downloads des Originals pro Tag | 10 | 50 |
HTTP/1.1 429 Too Many Requests
Retry-After: 41231
{
"error": {
"code": "quota_exceeded",
"message": "Daily limit reached: 10 proofs per account per UTC day across all its keys.",
"quota": {
"limit": 10,
"used": 10,
"resets_in_seconds": 41231
}
}
} Idempotenz
Sende bei POST /proofs einen Header Idempotency-Key (bis 200 Zeichen), dann kannst du gefahrlos wiederholen: Hast du ihn mit demselben API-Key schon benutzt, bekommst du den ursprünglichen Nachweis mit 200 und "created": false zurück, egal was der neue Body sagt, und es wird kein Zeitstempel ausgestellt.
Ohne den Header liefert das erneute Senden von Bytes, die deinem Konto schon gehören, ebenfalls den bestehenden Nachweis (200), ohne Name oder Metadaten zu ändern. Hat aber ein anderes Konto diese Bytes zuerst registriert, erzeugt jede Anfrage einen neuen Nachweis mit limitations: Wenn du wiederholen könntest, nutze immer Idempotency-Key.
Auch der Zeitstempel wird nie doppelt ausgestellt: Ein Nachweis hat genau einen, und eine erneute Anfrage liefert denselben, ohne einen weiteren zu verbrauchen.
Ohne Sellat prüfen
Ein Sellat-Nachweis braucht Sellat nicht, um geprüft zu werden. Mit der Datei und ihrer proof.json berechnet der Open-Source-Verifier den Fingerabdruck und den Merkle-Pfad neu und liest die Verankerung in der öffentlichen Blockchain.
Den qualifizierten Zeitstempel prüfst du mit OpenSSL, mit der Datei, der .tsr und dem Zertifikat der Zeitstempelstelle, das im Beweispaket liegt. -partial_chain ist nötig, weil die Vertrauensliste das Zertifikat der Stelle selbst veröffentlicht, nicht das einer CA.
# 1. The proof: file + proof.json + the public blockchain
curl https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json -o proof.json
npx sellat-verify contract.pdf proof.json
# 2. The qualified seal: file + .tsr + the authority's certificate
# (autoridad-sellado.pem comes inside evidence.zip)
openssl ts -verify -in seal.tsr -data contract.pdf \
-CAfile autoridad-sellado.pem -partial_chain Nachweise
Nachweis erstellen
POST /proofs
Registriert den SHA-256-Fingerabdruck einer Datei und gibt den Nachweis zurück. Mit "qualified": true stellt sie im selben Aufruf auch den qualifizierten Zeitstempel der FNMT aus und verbraucht dafür einen Zeitstempel des Kontos.
Parameter
-
hashPflicht - Der SHA-256-Fingerabdruck der Datei: 64 Hexadezimalzeichen.
-
nameoptional - Wie Dashboard und Zertifikat sie nennen. Gespeichert wird nur der Dateiname, ohne Pfad. Standard: die ersten 12 Zeichen des Hashs.
-
metadataoptional - Ein eigenes JSON-Objekt, bis 4 KB. Wird mit dem Nachweis gespeichert, aber nie zurückgegeben oder veröffentlicht.
-
sizeoptional - Dateigröße in Bytes. Informativ.
-
mime_typeoptional - Typ der Datei, genutzt beim Ausliefern des Originals, wenn du es verwahrst. Standard:
application/octet-stream. -
qualifiedoptional -
truestellt zusätzlich den qualifizierten Zeitstempel der FNMT aus. -
Idempotency-Keyoptional - Wiederholen ohne Duplikate (siehe Idempotenz).
Antworten
- 201
- Nachweis erstellt.
- 200
- Er existierte schon: Diese Bytes gehören bereits deinem Konto, oder du hast einen
Idempotency-Keywiederholt. Enthält"created": false. - 400
invalid_request: Ein Feld fehlt oder ist ungültig.- 401
unauthorized.- 402
payment_required: Zeitstempel angefordert, aber keiner mehr übrig. Es wird nichts geschrieben.- 409
conflict: Zeitstempel für Bytes angefordert, die ein anderes Konto zuerst registriert hat.- 429
quota_exceeded(Tageslimit) oderrate_limited(pro Minute).- 503
seal_unavailableoderunavailable. Wurde der Nachweis schon erstellt, enthält der Fehler seineproof_id.
Antwortet die Zeitstempelstelle langsam, wird der Nachweis trotzdem erstellt und qualified kommt als {"state": "pending"}: Fordere ihn mit POST /proofs/{id}/qualified erneut an, kostenlos.
Hat ein anderes Konto diese Bytes zuerst registriert, wird der Nachweis erstellt und verankert, aber ohne eigenes Zertifikat: Die Zertifikats-URLs sind null und die Antwort enthält "limitations": ["hash_registered_by_another_account"].
curl https://sellat.app/api/v2/proofs \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: contract-2026-0142" \
-d '{
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"name": "contract.pdf",
"qualified": true,
"metadata": { "ref": "case-2026-0142" }
}' {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"created": true,
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"algorithm": "SHA-256",
"name": "contract.pdf",
"state": "queued",
"received_at": "2026-09-30T09:12:03.418Z",
"anchors": [],
"bitcoin": {
"state": "pending",
"block_height": null
},
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"original": null,
"urls": {
"self": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"proof_json": "https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json",
"certificate": "https://sellat.app/certificate/3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b",
"certificate_pdf": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf",
"evidence_zip": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip"
}
} Nachweis abrufen
GET /proofs/{id}
Gibt den Nachweis mit Status, Verankerungen, Bitcoin-Bestätigung, dem Zeitstempel falls vorhanden, dem Original falls verwahrt, und allen URLs zurück.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
- Der Nachweis.
- 401
unauthorized.- 404
not_found: existiert nicht oder gehört einem anderen Konto.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"algorithm": "SHA-256",
"name": "contract.pdf",
"state": "anchored",
"received_at": "2026-09-30T09:12:03.418Z",
"anchors": [
{
"network": "Polygon Mainnet",
"chain_id": 137,
"state": "anchored",
"tx_hash": "0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a",
"block_number": 94653624,
"block_timestamp": "2026-09-30T09:14:36.000Z",
"explorer_url": "https://polygonscan.com/tx/0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a"
}
],
"bitcoin": {
"state": "pending",
"block_height": null
},
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"original": null,
"urls": {
"self": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"proof_json": "https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json",
"certificate": "https://sellat.app/certificate/3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b",
"certificate_pdf": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf",
"evidence_zip": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip"
}
} Nachweise auflisten
GET /proofs
Die Nachweise deines Kontos, neueste zuerst: aus der API und aus dem Web. Jedes Element in data ist ein vollständiger Nachweis wie bei GET /proofs/{id}.
Für die nächste Seite übergib den next_cursor der vorigen. Ist er null, gibt es keine weiteren.
Parameter
-
limitoptional - Nachweise pro Seite, 1 bis 100. Standard: 25.
-
cursoroptional - Der
next_cursorder vorigen Seite.
Antworten
- 200
dataundnext_cursor.- 400
invalid_request: ungültigeslimitodercursor.- 401
unauthorized.
curl "https://sellat.app/api/v2/proofs?limit=25" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"data": [
{
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"name": "contract.pdf",
"state": "confirmed",
"received_at": "2026-09-30T09:12:03.418Z"
}
],
"next_cursor": "1843"
} Qualifizierter Zeitstempel (eIDAS)
Qualifizierten Zeitstempel anfordern
POST /proofs/{id}/qualified
Stellt einen RFC-3161-Zeitstempel der FNMT-RCM über den Fingerabdruck der Datei aus. Nach Art. 41 Abs. 2 der eIDAS-Verordnung genießt ein qualifizierter elektronischer Zeitstempel die Vermutung der Richtigkeit des Datums und der Zeit, die er angibt, und der Unversehrtheit der Daten.
Verbraucht einen Zeitstempel des Kontos: den Willkommens-Zeitstempel oder einen aus deinen Paketen. Die API belastet nie eine Karte und öffnet keine Zahlung; Pakete kaufst du auf der Preisseite.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
- Zeitstempel ausgestellt, oder er war schon da (
"created": false, nichts verbraucht). Enthältseals_remaining. - 202
- Der Zeitstempel ist bezahlt, aber die Stelle hat nicht geantwortet. Erneut aufrufen (
Retry-After: 30): Er wird kostenlos abgeschlossen. - 401
unauthorized.- 402
payment_required: keine Zeitstempel mehr. Enthältseals_remainingundbuy_url.- 404
not_found.- 409
conflict: Ein anderes Konto hat diese Bytes zuerst registriert.- 503
seal_unavailable.
Ein Nachweis hat genau einen Zeitstempel, für immer. Scheitert die Ausstellung endgültig, kommt der Zeitstempel zurück in dein Guthaben.
curl -X POST https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"created": true,
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"seals_remaining": 4
} Zeitstempel abrufen
GET /proofs/{id}/qualified
Gibt nur den Zeitstempel des Nachweises zurück, oder null, wenn er noch keinen hat. Stellt nichts aus und verbraucht nichts.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
proof_idundqualified.- 401
unauthorized.- 404
not_found.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
}
} Token laden (.tsr)
GET /proofs/{id}/qualified.tsr
Der Zeitstempel genau so, wie die Stelle ihn geliefert hat: eine RFC-3161-TimeStampResp in DER. Diese Datei kann ein Gutachter oder ein Gericht ohne Sellat validieren.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
- Die
.tsr(application/timestamp-reply). - 401
unauthorized.- 404
not_found: Der Nachweis existiert nicht oder hat noch keinen Zeitstempel.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o seal.tsr HTTP/1.1 200 OK
Content-Type: application/timestamp-reply
Content-Disposition: attachment; filename="sellat-6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e-qualified-timestamp.tsr"
<RFC 3161 TimeStampResp, DER> Zertifikat und Beweise
PDF-Zertifikat
GET /proofs/{id}/certificate.pdf
Das Zertifikat des Nachweises, für Menschen: Fingerabdruck, Datum, Verankerungen und der qualifizierte Zeitstempel falls vorhanden, mit Anleitung zur Prüfung.
Parameter
-
idPflicht - Die
iddes Nachweises. -
langoptional - Sprache des Zertifikats:
es,en,deoderfr. Jeder andere Wert ergibten.
Antworten
- 200
- Das PDF.
- 401
unauthorized.- 404
not_found.- 409
conflict: Ein anderes Konto hat diese Bytes zuerst registriert, der Nachweis hat kein eigenes Zertifikat.
curl "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf?lang=es" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o certificate.pdf HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="certificado-3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b.pdf"
<PDF> Beweispaket
GET /proofs/{id}/evidence.zip
Ein ZIP mit allem, was man braucht, um den Nachweis ohne Sellat zu verteidigen: Zertifikat, proof.json, Zeitstempel und Zertifikat der Stelle falls vorhanden, die Anleitung und, wenn verwahrt, das Original.
Parameter
-
idPflicht - Die
iddes Nachweises. -
langoptional - Sprache der Texte im Paket:
es,en,deoderfr.
Antworten
- 200
- Das ZIP.
- 401
unauthorized.- 404
not_found.- 409
conflict: Ein anderes Konto hat diese Bytes zuerst registriert.
Das Original beizulegen verbraucht einen der Downloads des Tages. Sind keine mehr übrig, kommt das Paket ohne Original, und das README sagt es.
curl "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip?lang=es" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o evidence.zip HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="sellat-evidencia-3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b.zip"
<ZIP> Verwahrung des Originals
Original hinterlegen
PUT /proofs/{id}/original
Speichert die Datei neben ihrem Nachweis, auf Servern in der Europäischen Union. Sellat berechnet den Fingerabdruck des Empfangenen neu und lehnt ab, wenn er nicht zum Nachweis passt.
Sende die rohen Bytes mit dem Content-Type der Datei oder multipart/form-data im Feld file. POST funktioniert wie PUT.
Parameter
-
idPflicht - Die
iddes Nachweises. -
filePflicht - Die Datei. Bis 10 MB mit dem kostenlosen Konto und 50 MB mit dem Pro-Konto, und höchstens 25 MB pro Anfrage.
Antworten
- 201
- Gespeichert. Gibt den Nachweis mit
originalzurück. - 200
- War bereits gespeichert.
- 400
invalid_request: Body leer oder nicht lesbar.- 401
unauthorized.- 404
not_found.- 409
hash_mismatch(nicht die Datei des Nachweises) oderconflict(Bytes eines anderen Kontos).- 413
file_too_large: über dem Limit pro Datei deines Plans. Enthältmax_file_bytes.- 502
unavailable: Der Speicher hat nicht geantwortet.- 503
custody_unavailable.- 507
custody_quota_exceeded: kein Platz mehr in deinem Konto. Enthältused_bytesundmax_account_bytes.
Die Verwahrung ist optional: Der Nachweis gilt auch ohne Original. Sie ergänzt die Aufbewahrung, sie bedingt den Nachweis nicht.
curl -X PUT https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/pdf" \
--data-binary @contract.pdf {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"state": "anchored",
"original": {
"stored": true,
"file_name": "contract.pdf",
"size_bytes": 184320,
"mime_type": "application/pdf",
"stored_at": "2026-09-30T09:15:10.000Z",
"url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original"
}
} Original laden
GET /proofs/{id}/original
Gibt die verwahrte Datei zurück. Sellat berechnet ihren Fingerabdruck beim Ausliefern neu und verweigert die Auslieferung, wenn er nicht mehr passt. Jeder Download zählt zum Tageslimit deines Plans; der Header X-Sellat-Custody-Downloads-Remaining sagt, wie viele übrig sind.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
- Die Datei, mit Typ und Namen.
- 401
unauthorized.- 404
- Kein Original in Verwahrung.
- 409
conflict: Das Original ist noch nicht gespeichert.- 429
download_quota_exceeded: Tageslimit für Downloads. Neustart um 00:00 UTC.- 500
integrity_failed: Das Gespeicherte passt nicht mehr zum Fingerabdruck.- 502
unavailable.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o contract.pdf HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="contract.pdf"
X-Sellat-Custody-Downloads-Remaining: 9
<the original bytes> Verwahrung beenden
DELETE /proofs/{id}/original
Löscht das verwahrte Original. Der Nachweis ändert sich nicht: Er bleibt verankert, gestempelt und überprüfbar.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
"original": nullund"proof_unaffected": true."purged": falseheißt, dass die physische Löschung in der Warteschlange steht.- 401
unauthorized.- 404
- Kein Original in Verwahrung.
curl -X DELETE https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"original": null,
"purged": true,
"proof_unaffected": true
} Konto
Dein Konto
GET /account
Was der aufrufende Key kann: der Plan, deine übrigen Zeitstempel (Willkommen und Pakete), Verwahrungsplatz und Downloads, die heutigen Nachweise und ihr Limit, und die aktiven Keys. Frag es vor einem großen Batch ab.
Der Block connector enthält die Limits für verbundene Shops (WooCommerce, demnächst).
Antworten
- 200
- Das Konto.
- 401
unauthorized.
curl https://sellat.app/api/v2/account \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"plan": "free",
"plan_name": "Free",
"seals": {
"available": true,
"remaining": 1,
"welcome_remaining": 1,
"pack_remaining": 0,
"price_eur": 6,
"buy_url": "https://sellat.app/precios"
},
"custody": {
"available": true,
"used_bytes": 0,
"max_account_bytes": 52428800,
"max_file_bytes": 10485760,
"downloads_used_today": 0,
"max_downloads_per_day": 10
},
"proofs": {
"daily_limit": 10,
"used_today": 3,
"resets_in_seconds": 41231
},
"connector": {
"mode_available": "daily",
"eidas_available": false,
"custody_available": false,
"operations": {
"daily_limit": 2000,
"resets_in_seconds": 41231
}
},
"keys": {
"active": 1
},
"urls": {
"dashboard": "https://sellat.app/dashboard",
"plans": "https://sellat.app/precios#pricing-business",
"seals": "https://sellat.app/precios#pricing-seal-title",
"docs": "https://sellat.app/developers/docs",
"connect": "https://sellat.app/connect/woocommerce"
}
} Portabler Nachweis
Portabler Nachweis (proof.json)
GET /proof/{id}.json Ohne Key
Das Dokument, mit dem jeder den Nachweis ohne Sellat prüfen kann, im öffentlichen Format sellat-proof/2: Fingerabdruck, Blatt, Merkle-Pfad, Wurzel, Polygon-Verankerung und die Bestätigungen (Bitcoin und der qualifizierte Zeitstempel). Er ist absichtlich öffentlich: Wer ihn hat, kann den Nachweis ohne Konto prüfen.
Parameter
-
idPflicht - Die
iddes Nachweises.
Antworten
- 200
- Die
proof.json. - 202
- Noch nicht verankert:
{"ready": false, "state": "..."}mitRetry-After: 60. - 400
- Die
idist keine UUID. - 404
- Existiert nicht.
curl https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json -o proof.json {
"schema": "sellat-proof/2",
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"content": {
"algorithm": "SHA-256",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f"
},
"leaf": {
"formula": "SHA-256('sellat-leaf:v2:' + proof_id + ':' + content.hash)",
"value": "31668b4d846680cd920a1cb5be200ab0562909e8778223087c1738746a1cbb26"
},
"merkle": {
"index": 1,
"path": [
{
"position": "left",
"hash": "9e246a6d6dda91ee3916e149d834cd9a140e3470fbf5b6ec67824705dbbc82d4"
}
],
"root": "88fa1c4c3587d86d6f713e438c7ae745a91a6e03a5dd1b8282f17f35f30bfa14"
},
"anchors": [
{
"chain_id": 137,
"network": "Polygon Mainnet",
"tx_hash": "0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a",
"block_number": 94653624,
"payload": "sellat:v2:88fa1c4c3587d86d6f713e438c7ae745a91a6e03a5dd1b8282f17f35f30bfa14"
}
],
"attestations": [
{
"type": "opentimestamps",
"state": "submitted"
},
{
"type": "rfc3161-qualified-timestamp",
"state": "issued"
}
]
} Fehlt dir etwas, oder brauchst du mehr Volumen? Schreib an [email protected]: Du sprichst mit den Leuten, die den Code geschrieben haben.