TimeLayer API: one call, one receipt
The whole API is a single HTTP call. You hash an action or a document locally, send only the hash, and get back a self-contained receipt your user keeps and anyone verifies offline. Your content never leaves your machine.
Contents
1. Two minutes to your first receipt
- Create a free account at cabinet.timelayer-os.com — you get free receipts to start.
- Copy your API token from the cabinet.
- Hash anything and notarize it:
# hash a string (or a file with: shasum -a 256 file) HASH=$(printf 'invoice #4471 approved by alex@acme.com' | shasum -a 256 | cut -d' ' -f1) curl -X POST https://api.timelayer-os.com/v1/notarize \ -H "Authorization: Bearer $TL_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"action_hex\": \"$HASH\"}"
You get back a cert_hex and a bundle_hex. Decode them to bytes,
save as .tlcert and .tlbundle, and you hold a verifiable receipt.
2. Base URL & authentication
Base URL: https://api.timelayer-os.com. Every request carries your token as a
bearer header:
Authorization: Bearer <your API token>
Keep the token server-side
The token spends your receipt balance. Put it in an environment variable, never in client-side code or a public repo. You can see (and rotate) it in your cabinet.
3. POST /v1/notarize
The one endpoint. It takes the hash of whatever you want to prove and returns a receipt attesting exactly that hash.
| Field | Meaning |
|---|---|
| action_hex | Hex of the hash of your action or document. SHA-256 is the common choice; the binding is algorithm-neutral (SHA-256, BLAKE3, SHA-3…). Lowercase hex, no 0x prefix. |
Request body:
{ "action_hex": "b557d79ce260ed0edb9e548a9b3fe417967b6174f0e9c99ea28bfa1f27561c1e" }
Only the hash is sent. TimeLayer never sees your action or document — that is the point (Zero-Data): the network attests a fingerprint, not the contents.
4. The receipt: cert + bundle
A successful call returns two hex strings:
{
"cert_hex": "…", // the certificate, ~415 bytes decoded
"bundle_hex": "…" // its supporting evidence, ~1 KB decoded
}
These are raw bytes encoded as hex, not text. Decode each from hex and write the bytes to a file — the verifier reads the decoded bytes:
# bash
echo "$CERT_HEX" | xxd -r -p > receipt.tlcert
echo "$BUNDLE_HEX" | xxd -r -p > receipt.tlbundle
The pair travels with the action. Hand it to your user, embed it in a document, or store it in your database — there is no central log to keep, and nothing to trust us about later.
5. Verify offline
Anyone checks the receipt on their own machine, with no network and no account, using the open-source verifier:
timelayer-verifier verify receipt.tlcert receipt.tlbundle # -> VALID FINAL authentic and complete # -> UNVERIFIABLE forged, divergent, or tampered
To prove the receipt is about your exact action, pass the expected hash — a receipt that is valid in itself but attests something else is refused:
timelayer-verifier verify receipt.tlcert receipt.tlbundle --expect "$HASH"
6. Errors
Errors return a JSON body { "error": "…" }. On any doubt the API fails
closed — it never returns a half-valid receipt.
| Status | Body | Meaning & fix |
|---|---|---|
| 401 | (none) | No Authorization header. Add Bearer <token>. |
| 401 | AUTH FAIL | Token missing, wrong, or revoked. Copy a fresh token from the cabinet. |
| 401 | NOTARIZE FAIL reason=empty_action | action_hex is missing, empty, or not valid hex. Send lowercase hex of a real hash. |
7. Python & Node
# Python (stdlib only)
import hashlib, json, urllib.request, os
h = hashlib.sha256(b"invoice #4471 approved").hexdigest()
req = urllib.request.Request(
"https://api.timelayer-os.com/v1/notarize",
data=json.dumps({"action_hex": h}).encode(),
headers={"Authorization": f"Bearer {os.environ['TL_TOKEN']}",
"Content-Type": "application/json"}, method="POST")
r = json.load(urllib.request.urlopen(req))
open("receipt.tlcert", "wb").write(bytes.fromhex(r["cert_hex"]))
open("receipt.tlbundle","wb").write(bytes.fromhex(r["bundle_hex"]))
// Node 18+ (global fetch)
import { createHash } from "node:crypto";
import { writeFileSync } from "node:fs";
const hash = createHash("sha256").update("invoice #4471 approved").digest("hex");
const res = await fetch("https://api.timelayer-os.com/v1/notarize", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TL_TOKEN}`,
"Content-Type": "application/json" },
body: JSON.stringify({ action_hex: hash }),
});
const r = await res.json();
writeFileSync("receipt.tlcert", Buffer.from(r.cert_hex, "hex"));
writeFileSync("receipt.tlbundle", Buffer.from(r.bundle_hex, "hex"));
8. Balance & limits
Each successful notarization spends one receipt from your balance. New accounts start with a free allowance; after that you top up with a subscription or a one-time pack from your plans page — one-time packs never expire. Verifying receipts is always free and offline: it costs nothing and needs no token.
TimeLayer