Want to e-seal a file directly? Use Meerkat e-Seal Signer — paste a hash, get a signed .cms token, and inspect it inline. This page documents the raw HTTP API. 🔏 Open e-Seal Signer →
Testing only — do not use in production documents. The Meerkat e-Seal is not a qualified or accredited trust service. Signatures issued here carry no legal weight and must not be embedded in documents intended for production use. The e-Seal signing certificate is issued under a private, untrusted CA hierarchy that is not recognized by any public root store.

e-Seal Identity

Endpoint URL https://thameur.org/eseal
Signing Certificate /C=TN/O=Meerkat MPCA by Thameur Belghith/CN=e-Seal Signer
Valid From 2026-05-16
Valid Until 2029-05-15
Policy OID 2.16.788.1.99.1.60
Key Usage digitalSignature, nonRepudiation (critical)
Signing Key ECDSA P-256
Hash Algorithms SHA-256  ·  SHA-384  ·  SHA-512
e-Seal CA Certificate https://pki.thameur.org/mpca/eseal_ca.crt
Chain (CA + Root) http://pki.thameur.org/mpca/eseal_chain.pem
Standard eIDAS, ETSI EN 319 412-3, ETSI EN 319 122-1 (CAdES)

API Endpoint

MethodURLDescription
POST https://thameur.org/eseal Submit a JSON request with a hash digest. Returns a DER-encoded CMS SignedData. Primary endpoint.
GET https://thameur.org/eseal Redirects to this documentation page.

Request

Header / Body fieldPresenceNotes
Content-Type required Must be application/json
hash required Hex or base64-encoded digest of the document to seal. The algorithm is inferred from the byte length (32 → SHA-256, 48 → SHA-384, 64 → SHA-512). Spaces, colons, and dashes are stripped automatically.
alg optional Hint for the hash algorithm (sha256, sha384, sha512). Ignored — algorithm is always inferred from hash length.

Request Body Example

{ "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }

Success Response (HTTP 200)

Header / BodyValue
Content-Type application/cms
X-Eseal-Timestamped yes if an RFC 3161 signature timestamp was successfully embedded (CAdES-T); no if the TSA was unavailable and only a basic CAdES-B was returned.
Body DER-encoded CMS SignedData (RFC 5652) with an embedded id-aa-signatureTimeStampToken unsigned attribute (ETSI EN 319 122-1 §5.3.3 — CAdES-T). Contains the signed hash bytes as the encapsulated content, the signer certificate chain, and an RFC 3161 timestamp of the signature value from the Meerkat TSA.

Error Response (JSON)

{ "error": "human-readable error message" }

Integration Guide

If you just want to e-seal a file without writing any code, use 🔏 Meerkat e-Seal Signer — it handles the hash computation and API call for you and lets you download the token directly. The steps below are for integrating the e-Seal endpoint into your own tooling.

Step 1 — Compute the hash of your document

# SHA-256 (most common) sha256sum myfile.pdf | awk '{print $1}' # SHA-384 sha384sum myfile.pdf | awk '{print $1}' # SHA-512 sha512sum myfile.pdf | awk '{print $1}' # On macOS (use openssl) openssl dgst -sha256 myfile.pdf | awk '{print $2}'

Step 2 — Send the hash to the e-Seal endpoint

# Store the hash HASH=$(sha256sum myfile.pdf | awk '{print $1}') # Send to e-Seal endpoint curl -s -X POST https://thameur.org/eseal \ -H 'Content-Type: application/json' \ -d "{\"hash\": \"$HASH\"}" \ -o signature.cms # Inspect the CMS structure openssl asn1parse -inform DER -in signature.cms | head -40

Step 3 — Verify the e-Seal signature

# Download the e-Seal CA chain curl -s -o eseal_chain.pem http://pki.thameur.org/mpca/eseal_chain.pem # Verify the CMS signature (content is embedded in the token) openssl cms -verify -inform DER -in signature.cms \ -CAfile eseal_chain.pem -noverify -noout # Extract the signed content (should match your original hash bytes) openssl cms -verify -inform DER -in signature.cms \ -CAfile eseal_chain.pem -noverify | xxd

One-liner (hash + e-seal in one step)

curl -s -X POST https://thameur.org/eseal \ -H 'Content-Type: application/json' \ -d "{\"hash\": \"$(openssl dgst -sha256 myfile.pdf | awk '{print $2}')\"}" \ -o signature.cms \ && openssl asn1parse -inform DER -in signature.cms | head -30

Python (using the requests library)

import hashlib, requests # Compute SHA-256 hash with open('myfile.pdf', 'rb') as f: digest = hashlib.sha256(f.read()).hexdigest() # Send to e-Seal endpoint resp = requests.post( 'https://thameur.org/eseal', json={'hash': digest}, ) resp.raise_for_status() with open('signature.cms', 'wb') as f: f.write(resp.content)

JavaScript (Node.js)

const crypto = require('crypto'); const fs = require('fs'); const hash = crypto.createHash('sha256') .update(fs.readFileSync('myfile.pdf')) .digest('hex'); const response = await fetch('https://thameur.org/eseal', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ hash }), }); fs.writeFileSync('signature.cms', Buffer.from(await response.arrayBuffer()));

CMS SignedData Structure (RFC 5652)

FieldDescription
contentTypeid-signedData (1.2.840.113549.1.7.2)
versionv1 (1)
digestAlgorithmsHash algorithm inferred from the input (SHA-256, SHA-384, or SHA-512).
encapContentInfo.eContentTypeid-data (1.2.840.113549.1.7.1)
encapContentInfo.eContentThe raw hash bytes submitted in the request (embedded, non-detached).
certificatese-Seal signing certificate + e-Seal CA + Root CA (full chain).
signerInfo.digestAlgorithmSame as digestAlgorithms.
signerInfo.signatureAlgorithmECDSA with the matching SHA algorithm (e.g. ecdsa-with-SHA256).
signerInfo.signatureDER-encoded ECDSA signature over the signed attributes (which include the message digest of the content).
signerInfo.unsignedAttrs[0]id-aa-signatureTimeStampToken (OID 1.2.840.113549.1.9.16.2.14) — RFC 3161 TimeStampToken covering SHA-256(signatureValue). Sourced from the Meerkat TSA at signing time. This is the CAdES-T extension.

The signed content is the hash bytes you supplied, not your original document. This means the CMS token proves that the e-Seal signing key operated on those specific bytes — to tie it back to your document, you must independently verify that the hash bytes match the expected digest of your document.

Error Responses

Errors return JSON {"error": "..."} with the matching HTTP status code.

HTTPCause
400Missing or unparseable hash field, or hash decodes to wrong byte length (not 32, 48, or 64 bytes).
405Wrong HTTP method (only GET and POST are accepted).
415Wrong Content-Type — must be application/json.
500OpenSSL cms -sign failed — internal error. The error message contains the OpenSSL stderr output.
503e-Seal not initialized — the signing key or certificate is missing. Run scripts/mpca_init.sh.

Technical Notes