Documentation

Learn how to use OTRUST for timestamping, document signing, browser-generated range proofs, and issuer-gated Auth flows.

Timestamp

Prove when data existed using blockchain anchoring via OpenTimestamps.

Sign

Multi-party document signing with Ed25519 cryptographic signatures.

Proof Lab

Generate age and income range proofs locally, then verify them cryptographically.

Auth

Issuer-gated hosted Auth. Production challenges stay disabled until a trusted credential issuer is configured.

Privacy-First

Timestamp hashing and private range-proof inputs stay in your browser. Signing uses local-first flows where possible.

Web Tools

Use this section as the web entrypoint. Detailed flows live in the dedicated sections: Timestamp, Proof Lab, Sign, and Auth.

Open tools

  • Timestamp Tool for file and text claims, verify, compare, and browser-local receipt history.
  • Sign Tool for request creation, signer management, and signature status.
  • Proof Lab for local proof generation and independent verifier checks.
  • Auth Preview for the hosted issuer-bound integration surface.

Shared privacy model

  • Local-first processing: hashing and private proof inputs remain in the browser.
  • Minimal server data: store proofs, public signals, commitments, and verification metadata, not private inputs.
  • Independent verification: records can be checked without trusting private backend state alone.

SDK

Integrate OTRUST into your applications with official SDKs.

JavaScript / TypeScript

npm install @otrust/sdk

Quick Example

// Timestamp a file
import { timestamp, hashFile } from '@otrust/sdk'

const hash = await hashFile(file)
const result = await timestamp.create(hash)
console.log(result.id) // ot_xxx...

// Verify a timestamp
const verification = await timestamp.verify(hash)
console.log(verification.status) // 'confirmed'

Python

pip install otrust

Quick Example

# Timestamp a file
from otrust import timestamp, hash_file

hash = hash_file("document.pdf")
result = timestamp.create(hash)
print(result.id)  # ot_xxx...

# Verify
verification = timestamp.verify(hash)
print(verification.status)  # 'confirmed'

Available Modules

ModuleDescription
timestampCreate and verify blockchain timestamps
signMulti-party document signing
proofPrivacy-preserving ID packages
authHosted OTRUST Auth flows
sha256, hashFileHashing utilities
generateEd25519KeypairCryptographic key generation
Try in Playground →

React Components

npm install @otrust/react
import { TimestampWidget, LoginButton, IDBadge } from '@otrust/react'

// Ready-to-use timestamp widget
<TimestampWidget onSuccess={(id) => console.log(id)} />

// Login with OTRUST button
<LoginButton onAuth={(user) => setUser(user)} />

// Display ID verification badge
<IDBadge id="id_xxx" />

Configuration

Configure the SDK for custom deployments:

import { configure } from '@otrust/sdk'

configure({
  baseUrl: 'https://your-otrust-instance.com',
  timeout: 30000,
  retries: 3
})

Timestamp

Verify when data existed using Bitcoin blockchain anchoring.

Timestamp flow

  1. Your file is hashed locally (SHA-256)
  2. Only the hash is sent to OTRUST
  3. OTRUST aggregates hashes and creates a Merkle tree
  4. The Merkle root is anchored to Bitcoin via OpenTimestamps
  5. You receive a .ots receipt file for independent verification
Privacy: Your files never leave your device. Only the cryptographic hash is transmitted.

Use Cases

  • Research data – Prove when experiments were conducted
  • Creative works – Establish priority for ideas and designs
  • Legal documents – Prove document existence at a specific time
  • Code commits – Timestamp important software releases
  • Audit trails – Create immutable logs of business events

Receipt history (browser-local)

Your receipt list is stored in localStorage in the web tool and in chrome.storage.local in the extension. It is not uploaded to the server and cannot be listed by public key.

  • History tab – Shows timestamps created in this browser only
  • Encrypted backup – Keys tab → export/import password-protected JSON (keys + receipts + sign history)
  • Share proof – Download a share card (PNG) or copy verification text after creating a timestamp
  • Bitcoin toast – History tab polls pending receipts and notifies when Bitcoin confirms
API note: GET /receipts/:pubkey returns 410 Gone. Persist receipts client-side when you create them, or use individual /proof/:id URLs for verification.

Sign

Multi-party document signing with cryptographic evidence.

Signing flow

1
Upload your document

Choose local-hash mode or temporary encrypted upload when signers need a download link.

2
Add signing parties

Enter email addresses. Choose parallel or sequential signing.

3
Parties sign with Ed25519

Each signer generates a keypair and signs the document hash.

4
Anchored record

The complete signature package is anchored to Bitcoin via OpenTimestamps.

Start Signing →

Signing Order

ModeDescriptionUse Case
ParallelAll parties sign simultaneouslySimple agreements
SequentialMust sign in orderApproval chains

Party Roles

RoleAction
SignerMust cryptographically sign
ApproverMust approve (doesn't sign)
ViewerReceives copy only

Sign via Email

Create signing requests without leaving your inbox:

  • TO: People who should sign
  • CC: sign@otrust.eu
  • Attachment: Document to sign

Each party receives an email with Sign/Decline buttons.

Proof Lab

Generate Groth16 range proofs locally and submit only the proof, public signals, and commitment.

Range-proof flow

1
Choose a statement

Select an age or income range and enter the private value locally.

2
Generate locally

The browser uses the published circuit artifacts to create a Groth16 proof.

3
Inspect or export

The result contains the proof, public signals, and commitment, never the private value.

4
Publish when ready

The server verifies the proof before storing it and returning a public verification URL.

Open Proof Lab →

Supported proofs

TypePublic statementPrivate input
Age rangeThe committed age is inside the selected rangeDate of birth
Income rangeThe committed income is inside the selected rangeExact income
Meaning: A valid proof establishes consistency with a private value. It does not establish that the value came from a government, employer, bank, or other trusted issuer.

Production readiness

The circuits and browser artifacts are reproducible and the server performs Groth16 verification. Production publishing remains fail-closed until the public trusted-setup ceremony is complete.

  • At least two independent ceremony contributors are required.
  • A public final beacon must be recorded.
  • The published artifact manifest and checksums must pass verification.

Until then, local generation and export remain available while the publish endpoint returns a service-unavailable response in production.

Auth

Use trusted issuer-bound credentials for challenge-bound partner Auth.

Authentication flow

OTRUST Auth is an integration preview until a trusted credential issuer is configured. Production challenge creation fails closed before that capability is enabled.

1
User starts OTRUST Auth

Your app creates an authentication challenge.

2
User opens the hosted Auth URL

The user is redirected to OTRUST to present an issuer-bound credential.

3
Issuer credential verified

OTRUST verifies the current issuer binding, credential status, ownership, and challenge binding.

4
Callback with token and state

Your app receives a signed token and verifies it server-side before creating a session.

SDK Integration

Availability: Do not enable a production login button until /health reports identity_auth as ready. This requires both a trusted issuer and an exact client redirect allowlist.
// Create hosted Auth challenge
import { auth } from '@otrust/sdk'

const state = auth.generateState()
const challenge = await auth.createChallenge({
  clientId: 'my-app',
  redirectUri: 'https://yourapp.com/auth/callback',
  scope: ['identity'],
  state
})

// Redirect user to OTRUST
window.location.href = challenge.loginUrl

Verify Callback

// In your callback handler
const result = await auth.verify(token)

if (result.valid) {
  console.log(result.proofId) // id_xxx for audit
}

Partner Branding

Partners can attach an approved hosted-login theme to a client_id. The theme affects logo, colors, headline, spacing, radius, and footer copy on /auth/login?challenge=....

// Admin/dashboard save
PUT /admin/auth-branding/acme_prod
X-Admin-Key: <admin-key>

{
  "logoUrl": "https://example.com/assets/logo.svg",
  "backgroundColor": "#F8FAFC",
  "primaryColor": "#12324A",
  "textColor": "#0F1B2D",
  "fontFamily": "Inter",
  "borderRadius": 8,
  "spacingScale": "default",
  "headline": "Start Auth with Acme",
  "subhead": "Issuer-bound verification with OTRUST",
  "footerText": "Acme uses OTRUST as credential verifier",
  "autoRedirectSeconds": 3
}
Security: OTRUST disclosure, the OTRUST footer mark, and the DPO contact stay visible. Theme values are sanitized and all theme changes are written to the audit log.

React Component

import { LoginButton } from '@otrust/react'

<LoginButton
  scope={['identity']}
  onSuccess={(user) => {
    console.log(user.verified) // true
    console.log(user.proofId)   // id_xxx
  }}
/>

Available Claims

ClaimDescriptionUse Case
identityUser controls a current trusted issuer-bound credentialIssuer-backed account access
Privacy: Credential claims are verified without exposing raw identity documents to the partner application. Self-attested range proofs are not accepted as identity credentials.

Browser Extension

Timestamp any webpage with one click.

Installation

Available for Chrome, Chromium browsers (Edge, Brave), and Firefox (load unpacked).

Add to Chrome →

Manual Installation (Chrome / Firefox)

  1. Download extension.zip
  2. Extract to a folder
  3. Chrome: chrome://extensions → Developer mode → Load unpacked
  4. Firefox: about:debugging#/runtime/this-firefox → Load Temporary Add-on → select manifest.json

Usage

Click the OTRUST icon to:

  • Create timestamp – Hash page content locally, sign, and submit
  • Verify – Open verify flow with the current page hash
  • History – List receipts saved in this extension profile only (not synced to otrust.eu)
  • Email opt-in – Optional Bitcoin confirmation email

Extension history is separate from the web tool — each browser profile keeps its own list.

ChatGPT Integration

Timestamp conversations directly in ChatGPT.

Getting Started

  1. Open OTRUST Timestamper GPT
  2. Have a conversation
  3. Say "timestamp this conversation"
  4. Confirm the API call

Use Cases

  • AI-generated content – Prove when AI created text
  • Brainstorming – Timestamp ideas and discussions
  • Agreements – Record informal agreements
Note: OpenAI sees your conversation. For sensitive documents, use the Web Tool.

Email Timestamper

Timestamp emails by sending to timestamp@otrust.eu

Email flow

  1. Compose an email with content to timestamp
  2. Add attachments if needed
  3. Send to timestamp@otrust.eu
  4. Receive reply with claim ID and verification links

What Gets Timestamped

Subject, sender, date, body text, and attachment hashes are included in the hash.

Chat Bots

Timestamp messages in Telegram and WhatsApp.

Telegram Bot

Self-host the bot from addons/telegram-bot/ or use @OTRUSTbot when deployed.

Commands

  • /start or /help – Introduction
  • /hash <sha256> – Timestamp a 64-char hash via POST /claim/simple
  • Send a document – Hash file locally and timestamp
  • /status – Live anchored stats from /stats/badges.json
export TELEGRAM_BOT_TOKEN=...
export OTRUST_API=https://www.otrust.eu
cd addons/telegram-bot && npm start

WhatsApp Business

Enterprise feature requiring Meta Business verification.

Contact hello@otrust.eu for setup.

CLI Tool

Command-line interface for automation and scripting.

Installation

# Clone and install
git clone https://github.com/otrust-eu/opensource.git
cd opensource
npm install
npm link  # Makes 'otrust' command available

Commands

# Generate and save keypair
otrust keygen --save

# Timestamp a file or raw hash
otrust claim document.pdf
otrust claim a1b2c3...<64 hex>

# Verify a file or hash
otrust verify document.pdf

# Batch timestamp (max 100 files, one PoW)
otrust bulk ./docs/ --recursive

# Batch verify hashes
otrust verify-bulk ./docs/ -r --json

# Local CLI history (~/.otrust/history.json)
otrust history
otrust history --json

# Export IPFS-ready proof bundle
otrust ipfs-export ot_abc123xyz --out proof-bundle.json

Run otrust help for the full list. Email and webhook notifications are set via the API (notify_email, notify_webhook on POST /claim), not CLI flags.

Environment Variables

VariableDescription
OTRUST_APIAPI endpoint (default: https://www.otrust.eu)
OTRUST_KEYPath to Ed25519 key file (default: ~/.otrust/key.json)
OTRUST_HISTORYPath to local receipt history JSON

Scripting Examples

# Bash: timestamp all PDFs
for f in *.pdf; do otrust claim "$f"; done

# CI: batch timestamp release folder
otrust bulk dist/ --json

# Check proof metadata (curl)
curl -s "https://www.otrust.eu/proof/ot_abc123?format=json"

Embed & Webhooks

Trust badges, bookmarklets, and server callbacks for Bitcoin confirmation.

Embeddable trust badge

Show live anchored-record stats on your site:

<script src="https://www.otrust.eu/js/otrust-embed.js" data-otrust-badge></script>

See /embed for a preview. Data from /stats/badges.json.

<script src="https://www.otrust.eu/js/otrust-embed.js" data-otrust-badge data-otrust-theme="dark"></script>

Status page

Public ops view: /status (JSON: /status.json).

Webhook tester

Compute HMAC signatures for test payloads: /webhook-test.

Bookmarklet

Verify the current page without installing an extension. Drag the link from /bookmarklet to your bookmarks bar.

Bitcoin confirmation webhook

Pass notify_webhook (HTTPS only) and optional notify_webhook_secret on POST /claim, POST /claim/bulk, or POST /claim/simple. When OpenTimestamps confirms on Bitcoin, OTRUST POSTs once and deletes the webhook URL.

{
  "event": "bitcoin_confirmed",
  "receipt_id": "ot_abc123",
  "hash": "sha256-hex",
  "block_height": 912345,
  "proof_url": "https://www.otrust.eu/proof/ot_abc123",
  "ots_url": "https://www.otrust.eu/proof/ot_abc123?format=ots",
  "confirmed_at": "2026-07-04T14:00:00.000Z"
}

If notify_webhook_secret is set, verify header X-OTRUST-Signature: sha256=<hmac> (HMAC-SHA256 of the raw JSON body).

Alternatively use notify_email for a one-time confirmation email (deleted after send).

Self-Hosting

Run the open source OTRUST server, web UI, SDKs, CLI, and circuits from GitHub.

Included

  • Express server for timestamping, ID, signing, Auth, and verification APIs
  • Static web UI and OpenAPI documentation
  • TypeScript SDK
  • Python SDK
  • React components and hooks
  • CLI for hashing, timestamping, and verification
  • Circom circuits and browser extension source
  • Embedded SQLite storage with no separate database server
  • OpenTimestamps runtime bundled in the Docker image

Clone Repository

# Clone repository
git clone https://github.com/otrust-eu/opensource.git
cd opensource

# Install workspace dependencies
npm ci

The repository is self-hostable. Private OTRUST production infrastructure, partner themes, and service secrets are not included.

Run Locally

# Configure local environment
cp .env.example .env

# Start OTRUST with persistent SQLite storage
docker compose up -d --build

# Confirm storage and blockchain runtime status
curl -fsS http://localhost:3000/health

# Or run Node directly; data is stored in ./data
npm run dev

Persistent Storage

OTRUST stores application data in SQLite. OTRUST_DB_PATH defaults to ./data/otrust.sqlite. Docker Compose mounts the otrust_data volume at /app/data, so container rebuilds do not remove the database.

  • Back up the SQLite file or Docker volume before upgrades
  • Keep the database and otrust.sqlite.migration.json manifest together after a MongoDB migration
  • Set OTRUST_BACKUP_ENABLED=true with private BUCKET_* credentials for automatic S3-compatible backups
  • Automatic backups use VACUUM INTO, SQLite integrity checks, SHA-256 metadata, gzip compression, and configurable retention
  • Check storage.backup in /health and periodically perform an independent restore drill
  • On Railway, production startup refuses to create an empty SQLite database by default
  • Set OTRUST_ALLOW_EMPTY_DB=true only for a deliberate fresh production installation

Migrate from MongoDB

Stop writes, export each MongoDB collection as Extended JSON, and run a dry run before creating the SQLite database. The destination database must not already exist.

# Validate the export without writing a database
npm run migrate:mongodb-export -- \
  --source ./mongo-export \
  --db ./data/otrust.sqlite \
  --dry-run

# Create and verify the SQLite database
npm run migrate:mongodb-export -- \
  --source ./mongo-export \
  --db ./data/otrust.sqlite

The migration compares collection counts, record identities, canonical checksums, and SQLite integrity before writing the completion manifest. Follow the MongoDB migration guide for export, cutover, rollback, and backup steps.

OpenTimestamps Runtime

The Docker image includes the pinned OpenTimestamps 0.7.2 client and the digest bridge used to timestamp existing SHA-256 hashes. Native Node installations require the ots command and its Python package on PATH.

  • ENABLE_BLOCKCHAIN=false disables blockchain submission
  • OTS_CLI_COMMAND and OTS_PYTHON_COMMAND override runtime command paths
  • Calendar, quorum, and timeout settings are documented in .env.example
  • Check /health after startup to verify that the runtime is available

Verify Locally

# Core crypto tests
npm run test:core

# Build SDK packages
npm run build

# Use the CLI directly
node cli/otrust.js keygen
node cli/otrust.js verify 0000000000000000000000000000000000000000000000000000000000000000

Hosted API

PackageUseDefault API
sdk-jsBrowser and server JavaScript integrationshttps://otrust.eu
sdk-pythonPython automation and backend integrationshttps://otrust.eu
cliLocal hashing, signing, timestamping, and verificationhttps://www.otrust.eu

Repository

The clean open source repository is maintained separately from private production infrastructure.

Open GitHub Technical Changelog