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.

Basis-URL 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).

Anfrage
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.

Terminal
# 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.

StatusBedeutung
queuedEmpfangen. Wartet auf einen Batch, höchstens etwa zwei Minuten.
batchedIn einem Merkle-Batch, der Pfad steht fest. Wartet auf die Verankerung in Polygon.
anchoredVerankert: Die Transaktion steht in einem Polygon-Block. proof.json ist verfügbar.
confirmedDer 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.

CodeHTTPWas passiert ist
invalid_request400Ein Feld fehlt oder hat nicht das erwartete Format. Die Meldung sagt, welches.
unauthorized401Kein Key, ein fehlerhafter oder ein widerrufener Key.
payment_required402Keine qualifizierten Zeitstempel mehr. Enthält seals_remaining und buy_url.
key_without_account403Der Key gehört zu keinem Konto (alte Keys).
not_found404Der Nachweis existiert nicht oder gehört einem anderen Konto.
conflict409Ein anderes Konto hat diese Bytes zuerst registriert, oder das Original ist noch nicht gespeichert.
hash_mismatch409Die hochgeladene Datei hat nicht den Fingerabdruck des Nachweises.
file_too_large413Die Datei überschreitet das Limit pro Datei deines Plans (max_file_bytes).
rate_limited429Zu viele Anfragen pro Minute. Beachte Retry-After.
quota_exceeded429Tageslimit für Nachweise erreicht. Retry-After bis 00:00 UTC.
download_quota_exceeded429Tageslimit für Downloads des Originals erreicht.
integrity_failed500Das gespeicherte Original passt nicht mehr zu seinem Fingerabdruck und wird nicht ausgeliefert.
unavailable502 · 503Ein interner Dienst antwortet nicht. Später erneut versuchen.
seal_unavailable503Die Zeitstempelstelle ist gerade nicht erreichbar.
custody_unavailable503Die Verwahrung ist gerade nicht verfügbar.
custody_quota_exceeded507Kein Verwahrungsplatz mehr in deinem Konto.
Antwort
{
  "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 KontoPro-Konto
API-Nachweise pro Tag105.000
Aktive Keys55
Original in Verwahrung, pro Datei10 MB50 MB
Verwahrung insgesamt50 MB5 GB
Downloads des Originals pro Tag1050
Antwort
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.

Terminal
# 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

hash string · Body Pflicht
Der SHA-256-Fingerabdruck der Datei: 64 Hexadezimalzeichen.
name string · Body optional
Wie Dashboard und Zertifikat sie nennen. Gespeichert wird nur der Dateiname, ohne Pfad. Standard: die ersten 12 Zeichen des Hashs.
metadata object · Body optional
Ein eigenes JSON-Objekt, bis 4 KB. Wird mit dem Nachweis gespeichert, aber nie zurückgegeben oder veröffentlicht.
size integer · Body optional
Dateigröße in Bytes. Informativ.
mime_type string · Body optional
Typ der Datei, genutzt beim Ausliefern des Originals, wenn du es verwahrst. Standard: application/octet-stream.
qualified boolean · Body optional
true stellt zusätzlich den qualifizierten Zeitstempel der FNMT aus.
Idempotency-Key string · Header optional
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-Key wiederholt. 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) oder rate_limited (pro Minute).
503
seal_unavailable oder unavailable. Wurde der Nachweis schon erstellt, enthält der Fehler seine proof_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"].

Anfrage
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" }
  }'
Antwort
{
  "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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
Der Nachweis.
401
unauthorized.
404
not_found: existiert nicht oder gehört einem anderen Konto.
Anfrage
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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

limit integer · Query optional
Nachweise pro Seite, 1 bis 100. Standard: 25.
cursor string · Query optional
Der next_cursor der vorigen Seite.

Antworten

200
data und next_cursor.
400
invalid_request: ungültiges limit oder cursor.
401
unauthorized.
Anfrage
curl "https://sellat.app/api/v2/proofs?limit=25" \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
Zeitstempel ausgestellt, oder er war schon da ("created": false, nichts verbraucht). Enthält seals_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ält seals_remaining und buy_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.

Anfrage
curl -X POST https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
proof_id und qualified.
401
unauthorized.
404
not_found.
Anfrage
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
Die .tsr (application/timestamp-reply).
401
unauthorized.
404
not_found: Der Nachweis existiert nicht oder hat noch keinen Zeitstempel.
Anfrage
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr \
  -H "Authorization: Bearer $SELLAT_API_TOKEN" \
  -o seal.tsr
Antwort (Datei)
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

id string · Pfad Pflicht
Die id des Nachweises.
lang string · Query optional
Sprache des Zertifikats: es, en, de oder fr. Jeder andere Wert ergibt en.

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.
Anfrage
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
Antwort (Datei)
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

id string · Pfad Pflicht
Die id des Nachweises.
lang string · Query optional
Sprache der Texte im Paket: es, en, de oder fr.

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.

Anfrage
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
Antwort (Datei)
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

id string · Pfad Pflicht
Die id des Nachweises.
file binary · Body Pflicht
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 original zurü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) oder conflict (Bytes eines anderen Kontos).
413
file_too_large: über dem Limit pro Datei deines Plans. Enthält max_file_bytes.
502
unavailable: Der Speicher hat nicht geantwortet.
503
custody_unavailable.
507
custody_quota_exceeded: kein Platz mehr in deinem Konto. Enthält used_bytes und max_account_bytes.

Die Verwahrung ist optional: Der Nachweis gilt auch ohne Original. Sie ergänzt die Aufbewahrung, sie bedingt den Nachweis nicht.

Anfrage
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
Antwort
{
  "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

id string · Pfad Pflicht
Die id des 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.
Anfrage
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
  -H "Authorization: Bearer $SELLAT_API_TOKEN" \
  -o contract.pdf
Antwort (Datei)
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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
"original": null und "proof_unaffected": true. "purged": false heißt, dass die physische Löschung in der Warteschlange steht.
401
unauthorized.
404
Kein Original in Verwahrung.
Anfrage
curl -X DELETE https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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.
Anfrage
curl https://sellat.app/api/v2/account \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"
Antwort
{
  "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

id string · Pfad Pflicht
Die id des Nachweises.

Antworten

200
Die proof.json.
202
Noch nicht verankert: {"ready": false, "state": "..."} mit Retry-After: 60.
400
Die id ist keine UUID.
404
Existiert nicht.
Anfrage
curl https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json -o proof.json
Antwort
{
  "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.