DRAFT — not yet available. This page describes a feature whose development has not started yet. Everything below — field names, payload structure, headers and behaviour — may change before release, and the functionality is not available in any environment. Do not implement against it. This page will lose the DRAFT notice when the feature ships; the release it belongs to will be listed in the Release Notes.
Each document uploaded through Lean Disposable can be linked to a webhook URL, so that the preservation notification is sent to the endpoint you designate.
Example in the uploadDoc method:
{
"webhookUrl": "https://example.com/callback"
}The webhook settings include the following parameter.
- webhookUrl: The destination URL where the webhook notification will be sent.
- Must be a valid, publicly accessible URL
- HTTPS is required, on port 443
- The host must be a registered name — IP literals are rejected
- The URL must not embed credentials (no userinfo component before the host)
- Maximum length 2048 characters
- The host must be allowlisted for your account — see Host allowlist
Validation is synchronous: a URL that does not satisfy these rules makes the uploadDoc call fail with HTTP 400 and a dedicated application error code, so the problem surfaces at integration time rather than as silently undelivered notifications.
The webhook URL is defined per document, inline in the uploadDoc request. There is no global reusable configuration, and a document may have at most one webhook endpoint.
For details on notification payloads, retry behavior, and status transitions, see Understanding webhook.
Notification destinations are restricted to an allowlist of hosts, denied by default. The allowlist is populated by Namirial during onboarding: there is no API to register your own host, since that would defeat the control.
Provide the hosts you intend to use to your Namirial contact before going live. The host is also re-validated at delivery time, so a host that is later disabled stops receiving notifications even for documents already uploaded.
Namirial signs every outgoing notification and attaches the signature as an X-Namirial-Signature request header. This allows you to verify the authenticity and integrity of every notification.
The request headers of a notification are:
POST <webhookUrl>
Content-Type: application/json
X-Namirial-Signature: <compact JWS, detached payload>
X-Namirial-Event-Id: <eventId>The request body is sent in plain text. The signature is a JWS with detached payload (RFC 7797): the payload part of the token is empty and the signed content is the raw request body.
X-Namirial-Signature: <header>..<signature>The protected header, once base64url-decoded, looks like this:
{
"alg": "RS256",
"b64": false,
"crit": ["b64"],
"x5c": ["<leaf certificate, DER, Base64>", "<intermediate, DER, Base64>"],
"x5t#S256": "<SHA-256 thumbprint of the leaf certificate>"
}| Field | Description |
|---|---|
alg | The signing algorithm — always RS256 (RSASSA-PKCS1-v1_5 using SHA-256, as described in RFC7518 §3.1) |
b64 | Always false — the payload is detached and not base64url-encoded |
crit | Always ["b64"] — a verifier that does not understand b64 must reject the token |
x5c | The certificate chain, leaf first then intermediates. The root is not included |
x5t#S256 | SHA-256 thumbprint of the leaf certificate — use it to cache the chain validation result across notifications |
To verify a notification, follow these steps.
Step 1 — Validate the certificate chain
Decode the JWS header (the first part of the token, before the first .) from base64url to JSON and read the x5c array.
Validate the chain up to the Namirial root CA delivered to you at onboarding. The root is published on this documentation site together with its declared SHA-256 fingerprint, and it must be pinned in your application.
Never trust the embedded chain on its own. An attacker can sign a forged notification with their own certificate and embed that certificate in x5c. Only a chain that terminates in the pinned Namirial root proves the origin of the notification.
Then verify that:
- the leaf subject / SAN matches the value communicated at onboarding
- the leaf validity period covers the current time
- the leaf is not revoked (CRL or OCSP)
If any of these checks fails, the notification must be rejected without verifying the signature.
Step 2 — Rebuild the signed input
Because the payload is detached, the signed input is not carried in the token. Rebuild it as:
signed_input = <header> + "." + <raw request body>where <header> is the first part of the X-Namirial-Signature value, exactly as received (still base64url-encoded), and <raw request body> is the request body byte for byte, with no re-serialization, no whitespace normalization and no key reordering.
Step 3 — Verify the signature
Using the algorithm specified in alg and the public key of the leaf certificate validated in step 1, verify that the signature (the third part of the token) is a valid signature of signed_input.
If the verification fails, the notification must be rejected.
token = request.headers["x-namirial-signature"]
parts = token.split(".") // parts[1] is empty: detached payload
header = base64url_decode(parts[0])
signature = base64url_decode(parts[2])
chain = header["x5c"]
assert validate_chain(chain, pinned_namirial_root) // step 1
assert leaf_not_revoked(chain[0])
signed_input = parts[0] + "." + raw_request_body
public_key = public_key_of(chain[0])
assert rsa_sha256_verify(public_key, signed_input, signature)Step 4 — Deduplicate and answer
Delivery is at-least-once. Deduplicate on the eventId field of the payload (also available in the X-Namirial-Event-Id header) and answer HTTP 200 once the event has been accepted.
Any status other than 200 — including 202 and 204 — causes redelivery for up to 24 hours. See Webhook Retry Mechanism.