docs: Application Client developers page and OpenAPI on site
This commit is contained in:
parent
d24721ce8a
commit
6be2afd683
4 changed files with 1002 additions and 0 deletions
268
site/developers.html
Normal file
268
site/developers.html
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Application Client · Developers</title>
|
||||||
|
<meta name="description" content="Non-AI Application Client for Verae timestamps: OpenAPI, Python, TypeScript, curl VeraeTime global, curl MCP local. Digests only.">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="icon" href="assets/VeraeFullLogo.png">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--ink: oklch(0.21 0.020 310);
|
||||||
|
--ink-soft: oklch(0.42 0.018 310);
|
||||||
|
--ink-mute: oklch(0.60 0.014 310);
|
||||||
|
--paper: oklch(0.992 0.004 90);
|
||||||
|
--soft: oklch(0.972 0.008 85);
|
||||||
|
--hair: oklch(0.90 0.010 80);
|
||||||
|
--purple: oklch(0.32 0.110 310);
|
||||||
|
--purple-mid: oklch(0.42 0.130 312);
|
||||||
|
--purple-wash: oklch(0.96 0.020 312);
|
||||||
|
--gold: oklch(0.80 0.090 85);
|
||||||
|
--dark: oklch(0.19 0.022 312);
|
||||||
|
--ok: oklch(0.55 0.12 145);
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
color: var(--ink);
|
||||||
|
background: var(--paper);
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
a { color: var(--purple); }
|
||||||
|
header {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
max-width: 1100px; margin: 0 auto; padding: 28px 28px 0; flex-wrap: wrap; gap: 12px;
|
||||||
|
}
|
||||||
|
.brand img { height: 46px; width: auto; display: block; }
|
||||||
|
nav { display: flex; gap: 22px; font-size: 14px; font-weight: 600; flex-wrap: wrap; }
|
||||||
|
nav a { color: var(--ink-soft); text-decoration: none; }
|
||||||
|
nav a:hover, nav a.active { color: var(--purple); }
|
||||||
|
.hero { max-width: 1100px; margin: 0 auto; padding: 48px 28px 12px; }
|
||||||
|
.eyebrow {
|
||||||
|
font-size: 13px; font-weight: 700; letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase; color: var(--purple-mid);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-family: Fraunces, Georgia, serif; font-weight: 560;
|
||||||
|
font-size: clamp(34px, 5vw, 56px); line-height: 1.08;
|
||||||
|
letter-spacing: -0.03em; margin: 12px 0 18px; max-width: 22ch;
|
||||||
|
}
|
||||||
|
.lede { max-width: 46rem; font-size: 18px; color: var(--ink-soft); margin: 0; }
|
||||||
|
.gold { height: 3px; width: 72px; background: var(--gold); border: 0; margin: 28px 0; }
|
||||||
|
.wrap { max-width: 1100px; margin: 0 auto; padding: 12px 28px 80px; }
|
||||||
|
h2.section {
|
||||||
|
font-family: Fraunces, Georgia, serif; font-size: 30px; font-weight: 560; margin: 48px 0 8px;
|
||||||
|
}
|
||||||
|
.section-note { color: var(--ink-soft); max-width: 48rem; margin-top: 0; }
|
||||||
|
.card {
|
||||||
|
background: white; border: 1px solid var(--hair); border-radius: 16px; padding: 22px; margin-top: 18px;
|
||||||
|
}
|
||||||
|
.card.featured {
|
||||||
|
border-color: color-mix(in oklch, var(--purple) 35%, var(--hair));
|
||||||
|
background: linear-gradient(180deg, var(--purple-wash), white 48%);
|
||||||
|
}
|
||||||
|
.btn-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 14px; }
|
||||||
|
.btn {
|
||||||
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
|
background: var(--purple); color: white; text-decoration: none; border: 0;
|
||||||
|
border-radius: 999px; padding: 12px 18px; font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
|
||||||
|
}
|
||||||
|
.btn.secondary { background: white; color: var(--purple); border: 1px solid var(--hair); }
|
||||||
|
.meta { font-size: 13px; color: var(--ink-mute); margin-top: 12px; }
|
||||||
|
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; }
|
||||||
|
.path { background: var(--purple-wash); padding: 2px 6px; border-radius: 6px; }
|
||||||
|
pre {
|
||||||
|
background: var(--dark); color: oklch(0.95 0.01 90); border-radius: 14px;
|
||||||
|
padding: 16px 18px; overflow: auto;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.5; margin: 12px 0 0;
|
||||||
|
}
|
||||||
|
table.split {
|
||||||
|
width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 14px;
|
||||||
|
}
|
||||||
|
table.split th, table.split td {
|
||||||
|
text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--hair); vertical-align: top;
|
||||||
|
}
|
||||||
|
table.split th {
|
||||||
|
color: var(--ink-mute); font-weight: 600; font-size: 12px;
|
||||||
|
text-transform: uppercase; letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
border-top: 1px solid var(--hair); padding: 28px; color: var(--ink-mute); font-size: 14px;
|
||||||
|
}
|
||||||
|
footer .inner { max-width: 1100px; margin: 0 auto; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
nav { gap: 14px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<a class="brand" href="https://www.verae.com/"><img src="assets/VeraeFullLogo.png" alt="Verae"></a>
|
||||||
|
<nav>
|
||||||
|
<a href="index.html">Install</a>
|
||||||
|
<a href="ways.html">Ways to use</a>
|
||||||
|
<a href="developers.html" class="active">Developers</a>
|
||||||
|
<a href="sample.html">Sample</a>
|
||||||
|
<a href="hasher.html">Hasher</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="hero">
|
||||||
|
<p class="eyebrow">Application Client · OpenAPI</p>
|
||||||
|
<h1>Build without an AI host</h1>
|
||||||
|
<p class="lede">Stamp, verify, and look up digests from Python, TypeScript, or raw HTTP. Paths in the OpenAPI file are <strong>logical SDK operations</strong> — not deployed REST routes on this host. File bytes never leave the client; only SHA-256 digests are sent.</p>
|
||||||
|
<hr class="gold">
|
||||||
|
</section>
|
||||||
|
<div class="wrap">
|
||||||
|
<section id="overview">
|
||||||
|
<h2 class="section">Overview</h2>
|
||||||
|
<p class="section-note">The Application Client routes by scope: <code>global</code> hits VeraeTime directly; <code>local</code> / <code>shared</code> use MCP Streamable HTTP at <code>/mcp</code>. SDKs refuse content-byte argument names (<code>content</code>, <code>bytes</code>, <code>file</code>, <code>data</code>, <code>path</code>, <code>body</code>, <code>payload</code>, <code>blob</code>, <code>archive</code>).</p>
|
||||||
|
<div class="card featured">
|
||||||
|
<p style="margin:0;color:var(--ink-soft);font-size:15px">Defaults: MCP <code>https://mcp.verae.ai/mcp</code> · VeraeTime <code>https://api.veraetime.net</code>. Global stamp sends <code>restamp: false</code> (reuse an existing certificate when present).</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="openapi/application-client.yaml">OpenAPI YAML</a>
|
||||||
|
<a class="btn secondary" href="ways.html">Ways to use hub</a>
|
||||||
|
<a class="btn secondary" href="sample.html">Browser MCP sample</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="transport">
|
||||||
|
<h2 class="section">Transport split</h2>
|
||||||
|
<p class="section-note">One Application API surface; two backends. Auth ops always use VeraeTime with a caller-held JWT.</p>
|
||||||
|
<table class="split">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Operation</th>
|
||||||
|
<th>local / shared</th>
|
||||||
|
<th>global</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>stamp</code></td>
|
||||||
|
<td>MCP tool <code>stamp</code></td>
|
||||||
|
<td>VeraeTime <code>POST /api/timestamp</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>verify</code></td>
|
||||||
|
<td>MCP tool <code>verify</code></td>
|
||||||
|
<td>VeraeTime <code>POST /api/verify</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>hash_report</code></td>
|
||||||
|
<td>MCP tool <code>hash_report</code></td>
|
||||||
|
<td>VeraeTime <code>GET /api/hash/{sha256}</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>signup / login / session / create_user</td>
|
||||||
|
<td colspan="2">VeraeTime <code>/auth/*</code> (direct; apps do not rely on MCP account tools)</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="openapi">
|
||||||
|
<h2 class="section">OpenAPI</h2>
|
||||||
|
<p class="section-note">Normative digests-only contract for the Application Client SDKs (OpenAPI 3.1). Download or fetch from this site:</p>
|
||||||
|
<pre>https://mcp.verae.ai/openapi/application-client.yaml</pre>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="openapi/application-client.yaml">application-client.yaml</a>
|
||||||
|
</div>
|
||||||
|
<p class="meta">Logical paths such as <code>/stamp</code> document SDK methods; they are not HTTP routes on <code>mcp.verae.ai</code> in this phase.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="python">
|
||||||
|
<h2 class="section">Python</h2>
|
||||||
|
<p class="section-note">Package <code>verae-mcp-timestamping-client</code> — <code>ApplicationClient</code> routes by scope.</p>
|
||||||
|
<pre>import asyncio
|
||||||
|
from verae_mcp_timestamping_client import ApplicationClient
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
client = ApplicationClient()
|
||||||
|
print(await client.stamp("<64-hex>", scope="global"))
|
||||||
|
print(await client.stamp("<64-hex>", scope="local"))
|
||||||
|
|
||||||
|
asyncio.run(main())</pre>
|
||||||
|
<p class="meta">Install: <code>uv add verae-mcp-timestamping-client</code> or <code>pip install verae-mcp-timestamping-client</code>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="typescript">
|
||||||
|
<h2 class="section">TypeScript</h2>
|
||||||
|
<p class="section-note">Package <code>@verae/timestamping-client</code>. Method names are camelCase (<code>hashReport</code>); OpenAPI stays snake_case.</p>
|
||||||
|
<pre>import { ApplicationClient } from "@verae/timestamping-client";
|
||||||
|
|
||||||
|
const client = new ApplicationClient({ token: process.env.VERAE_GLOBAL_TOKEN });
|
||||||
|
|
||||||
|
// Global → VeraeTime POST /api/timestamp (restamp: false)
|
||||||
|
const global = await client.stamp("a".repeat(64), { scope: "global" });
|
||||||
|
|
||||||
|
// Local → MCP tools/call stamp
|
||||||
|
const local = await client.stamp("a".repeat(64), { scope: "local" });</pre>
|
||||||
|
<p class="meta">Install: <code>npm install @verae/timestamping-client</code>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="curl-global">
|
||||||
|
<h2 class="section">curl · global (VeraeTime)</h2>
|
||||||
|
<p class="section-note">Direct HTTPS to <code>api.veraetime.net</code>. Bearer token from env or <span class="path">~/.verae/auth.properties</span>.</p>
|
||||||
|
<pre># TOKEN from VERAE_GLOBAL_TOKEN or access_token in ~/.verae/auth.properties
|
||||||
|
DIGEST=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||||
|
|
||||||
|
curl -sS -X POST https://api.veraetime.net/api/timestamp \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-d "{\"data\":\"$DIGEST\",\"digest\":\"$DIGEST\",\"hashAlg\":\"SHA256\",\"restamp\":false}"</pre>
|
||||||
|
<p class="meta">On <code>200</code> with <code>certificate</code> / <code>existing</code>, reuse that CID. Otherwise poll <code>GET /api/status/{jobId}</code>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="curl-mcp">
|
||||||
|
<h2 class="section">curl · MCP local</h2>
|
||||||
|
<p class="section-note">Streamable HTTP at <code>/mcp</code>. Capture <code>Mcp-Session-Id</code> from <code>initialize</code>, then <code>notifications/initialized</code>, then <code>tools/call</code>.</p>
|
||||||
|
<pre># 1) initialize — note Mcp-Session-Id in response headers
|
||||||
|
curl -sS -D - -X POST https://mcp.verae.ai/mcp \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json, text/event-stream' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"dev-curl","version":"1.0.0"}}}'
|
||||||
|
|
||||||
|
# 2) notifications/initialized (same session)
|
||||||
|
curl -sS -X POST https://mcp.verae.ai/mcp \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json, text/event-stream' \
|
||||||
|
-H 'Mcp-Session-Id: SESSION' \
|
||||||
|
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
|
||||||
|
|
||||||
|
# 3) tools/call stamp (local scope)
|
||||||
|
curl -sS -X POST https://mcp.verae.ai/mcp \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json, text/event-stream' \
|
||||||
|
-H 'Mcp-Session-Id: SESSION' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"stamp","arguments":{"sha256":"DIGEST_HEX","scope":"local"}}}'</pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="auth">
|
||||||
|
<h2 class="section">Auth</h2>
|
||||||
|
<p class="section-note">Machine login writes a JWT under <span class="path">~/.verae/auth.properties</span> (mode <code>600</code>). Do not paste tokens into chat or commit the file.</p>
|
||||||
|
<div class="card">
|
||||||
|
<p style="margin:0 0 8px;color:var(--ink-soft);font-size:15px"><strong>Resolve order</strong> (Application Client / VeraeTime transport): constructor token → <code>VERAE_GLOBAL_TOKEN</code> → <code>access_token</code> / <code>auth_token</code> / <code>id_token</code> in auth.properties (<code>VERAE_AUTH_PROPERTIES</code> overrides the path).</p>
|
||||||
|
<pre>uvx verae-mcp-timestamping-server setup
|
||||||
|
# writes ~/.verae/auth.properties (mode 600); does not print the token
|
||||||
|
uvx verae-mcp-timestamping-server session</pre>
|
||||||
|
<p class="meta">Keys typically include <code>access_token</code>, <code>expires_at</code>, and username. Directory <code>~/.verae</code> is mode <code>700</code>.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<div class="inner">
|
||||||
|
<span>Verae timestamping · <a href="https://www.verae.com/">verae.com</a></span>
|
||||||
|
<span><a href="index.html">Install</a> · <a href="ways.html">Ways to use</a> · <a href="developers.html">Developers</a> · <a href="openapi/application-client.yaml">OpenAPI</a> · <a href="sample.html">Sample</a></span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -168,6 +168,8 @@
|
||||||
<a href="#hasher">Hasher</a>
|
<a href="#hasher">Hasher</a>
|
||||||
<a href="#connect">Connect</a>
|
<a href="#connect">Connect</a>
|
||||||
<a href="#register">Register</a>
|
<a href="#register">Register</a>
|
||||||
|
<a href="ways.html">Ways to use</a>
|
||||||
|
<a href="developers.html">Developers</a>
|
||||||
<a href="sample.html">Try a stamp</a>
|
<a href="sample.html">Try a stamp</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
374
site/openapi/application-client.yaml
Normal file
374
site/openapi/application-client.yaml
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Verae Application Client API
|
||||||
|
version: 0.1.0
|
||||||
|
description: |
|
||||||
|
Digests-only Application Client API for non-AI apps. Paths below are **logical**
|
||||||
|
documentation identifiers for the client SDKs (Python / TypeScript); they are **not**
|
||||||
|
deployed server routes on `mcp.verae.ai` in this phase.
|
||||||
|
|
||||||
|
**Defaults:** MCP Streamable HTTP `https://mcp.verae.ai/mcp`; VeraeTime
|
||||||
|
`https://api.veraetime.net`.
|
||||||
|
|
||||||
|
**Digests only:** stamp / verify / hash_report accept SHA-256 digests. SDKs refuse
|
||||||
|
arguments named `content`, `bytes`, `file`, `data`, `path`, `body`, `payload`,
|
||||||
|
`blob`, or `archive`.
|
||||||
|
|
||||||
|
**Global stamp:** VeraeTime body uses `restamp: false` by default (reuse existing
|
||||||
|
certificate). Explicit restamp is out of scope unless added later.
|
||||||
|
|
||||||
|
## Mapping appendix (MCP ↔ VeraeTime ↔ Application API)
|
||||||
|
|
||||||
|
| Application op | MCP tool | VeraeTime |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| stamp local/shared | `stamp` | — |
|
||||||
|
| stamp global | — | `POST /api/timestamp` |
|
||||||
|
| verify (non-global) | `verify` | — |
|
||||||
|
| verify global | — | `POST /api/verify` |
|
||||||
|
| hash_report (non-global) | `hash_report` | — |
|
||||||
|
| hash_report global | — | `GET /api/hash/{sha256}` |
|
||||||
|
| signup | (`signup` exists on MCP; apps use direct) | `POST /auth/signup` |
|
||||||
|
| login | (`login` exists on MCP; apps use direct) | `POST /auth/login` |
|
||||||
|
| session | (`session` exists on MCP; apps use direct) | `GET /auth/validate` |
|
||||||
|
| create_user | (`create_user` exists on MCP; apps use direct) | `POST /auth/users` |
|
||||||
|
|
||||||
|
Routing: `local` / `shared` stamp and non-global verify / hash_report use MCP.
|
||||||
|
`global` / `want_scope=global` use VeraeTime directly. Auth ops always hit VeraeTime
|
||||||
|
with caller-held JWTs.
|
||||||
|
servers:
|
||||||
|
- url: https://mcp.verae.ai
|
||||||
|
description: >
|
||||||
|
Logical base for documentation only. Application Client SDK paths are not
|
||||||
|
deployed HTTP routes; local/shared ops use MCP at https://mcp.verae.ai/mcp.
|
||||||
|
- url: https://api.veraetime.net
|
||||||
|
description: >
|
||||||
|
VeraeTime direct HTTPS for global stamp/verify/hash_report and all auth ops.
|
||||||
|
Application Client paths still map to /api/* and /auth/* as in the appendix.
|
||||||
|
paths:
|
||||||
|
/stamp:
|
||||||
|
post:
|
||||||
|
operationId: stamp
|
||||||
|
summary: Stamp a SHA-256 digest
|
||||||
|
description: |
|
||||||
|
Request a timestamp for a digest. Scope `local` or `shared` goes to MCP tool
|
||||||
|
`stamp`; scope `global` goes to VeraeTime `POST /api/timestamp` with
|
||||||
|
`restamp: false` by default.
|
||||||
|
tags: [timestamping]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/StampRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: One or more normalized receipts
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/StampResponse"
|
||||||
|
/verify:
|
||||||
|
post:
|
||||||
|
operationId: verify
|
||||||
|
summary: Verify a receipt
|
||||||
|
description: |
|
||||||
|
Verify by `receipt_id`. Use `want_scope=global` (or a global receipt) for
|
||||||
|
VeraeTime `POST /api/verify`; otherwise MCP tool `verify`.
|
||||||
|
tags: [timestamping]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/VerifyRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Verification result
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/VerifyResponse"
|
||||||
|
/hash_report:
|
||||||
|
post:
|
||||||
|
operationId: hash_report
|
||||||
|
summary: List receipts for a digest
|
||||||
|
description: |
|
||||||
|
History for a SHA-256 digest. `want_scope=global` uses VeraeTime
|
||||||
|
`GET /api/hash/{sha256}`; otherwise MCP tool `hash_report`. Empty history
|
||||||
|
is `{ "receipts": [] }`.
|
||||||
|
tags: [timestamping]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/HashReportRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Receipts for the digest (possibly empty)
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/HashReportResponse"
|
||||||
|
/signup:
|
||||||
|
post:
|
||||||
|
operationId: signup
|
||||||
|
summary: Create an account on VeraeTime
|
||||||
|
description: |
|
||||||
|
Always `POST https://api.veraetime.net/auth/signup`. Does not replace the
|
||||||
|
stored JWT; caller must `login` for a session.
|
||||||
|
tags: [auth]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/SignupRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Created user
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/AuthUserResponse"
|
||||||
|
/login:
|
||||||
|
post:
|
||||||
|
operationId: login
|
||||||
|
summary: Login and obtain caller-held JWT
|
||||||
|
description: |
|
||||||
|
Always `POST https://api.veraetime.net/auth/login`. SDK stores JWT in
|
||||||
|
caller-local secure storage (`~/.verae/auth.properties` on native). JWT
|
||||||
|
values are never logged.
|
||||||
|
tags: [auth]
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/LoginRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Authenticated user session metadata
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/AuthUserResponse"
|
||||||
|
/session:
|
||||||
|
get:
|
||||||
|
operationId: session
|
||||||
|
summary: Validate current session
|
||||||
|
description: |
|
||||||
|
Always `GET https://api.veraetime.net/auth/validate` with bearer from
|
||||||
|
constructor, `VERAE_GLOBAL_TOKEN`, or auth.properties.
|
||||||
|
tags: [auth]
|
||||||
|
security:
|
||||||
|
- bearerAuth: []
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Session validity
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/SessionResponse"
|
||||||
|
/create_user:
|
||||||
|
post:
|
||||||
|
operationId: create_user
|
||||||
|
summary: Create a user (admin)
|
||||||
|
description: |
|
||||||
|
Always `POST https://api.veraetime.net/auth/users`. Requires admin bearer.
|
||||||
|
tags: [auth]
|
||||||
|
security:
|
||||||
|
- bearerAuth: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/CreateUserRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Created user
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/AuthUserResponse"
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
bearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
description: Caller-held VeraeTime JWT (never logged).
|
||||||
|
schemas:
|
||||||
|
Receipt:
|
||||||
|
type: object
|
||||||
|
description: Shared normalized receipt object across MCP and VeraeTime.
|
||||||
|
required:
|
||||||
|
- receipt_id
|
||||||
|
- hash
|
||||||
|
- scope
|
||||||
|
- created_at
|
||||||
|
- merkle
|
||||||
|
properties:
|
||||||
|
receipt_id:
|
||||||
|
type: string
|
||||||
|
description: Local id or VeraeTime certificate CID
|
||||||
|
hash:
|
||||||
|
type: string
|
||||||
|
description: SHA-256 hex (64 characters)
|
||||||
|
pattern: "^[0-9a-fA-F]{64}$"
|
||||||
|
scope:
|
||||||
|
type: string
|
||||||
|
description: local, shared, or global
|
||||||
|
enum: [local, shared, global]
|
||||||
|
cube_id:
|
||||||
|
type: string
|
||||||
|
description: Optional; local metadata
|
||||||
|
org_id:
|
||||||
|
type: string
|
||||||
|
description: Optional; local idempotency key; ignored by VeraeTime
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
description: Timestamp when available
|
||||||
|
merkle:
|
||||||
|
type: string
|
||||||
|
description: Block hash / index when available
|
||||||
|
restamp_of:
|
||||||
|
type: string
|
||||||
|
description: Prior certificate when restamped
|
||||||
|
StampRequest:
|
||||||
|
type: object
|
||||||
|
required: [sha256]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
sha256:
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
SHA-256 digest (64 hex). Optional `sha256:` prefix is stripped by SDKs.
|
||||||
|
minLength: 64
|
||||||
|
scope:
|
||||||
|
type: string
|
||||||
|
description: Default local. global → VeraeTime with restamp false.
|
||||||
|
enum: [local, shared, global]
|
||||||
|
default: local
|
||||||
|
cube_id:
|
||||||
|
type: string
|
||||||
|
org_id:
|
||||||
|
type: string
|
||||||
|
StampResponse:
|
||||||
|
type: object
|
||||||
|
required: [receipts]
|
||||||
|
properties:
|
||||||
|
receipts:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Receipt"
|
||||||
|
VerifyRequest:
|
||||||
|
type: object
|
||||||
|
required: [receipt_id]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
receipt_id:
|
||||||
|
type: string
|
||||||
|
want_scope:
|
||||||
|
type: string
|
||||||
|
description: Set to global to force VeraeTime verify.
|
||||||
|
enum: [local, shared, global]
|
||||||
|
VerifyResponse:
|
||||||
|
type: object
|
||||||
|
required: [valid, error, receipt]
|
||||||
|
properties:
|
||||||
|
valid:
|
||||||
|
type: boolean
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
receipt:
|
||||||
|
nullable: true
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/Receipt"
|
||||||
|
HashReportRequest:
|
||||||
|
type: object
|
||||||
|
required: [sha256]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
sha256:
|
||||||
|
type: string
|
||||||
|
description: SHA-256 digest (64 hex; optional sha256: prefix stripped)
|
||||||
|
minLength: 64
|
||||||
|
org_id:
|
||||||
|
type: string
|
||||||
|
want_scope:
|
||||||
|
type: string
|
||||||
|
description: Set to global to force VeraeTime hash lookup.
|
||||||
|
enum: [local, shared, global]
|
||||||
|
HashReportResponse:
|
||||||
|
type: object
|
||||||
|
required: [receipts]
|
||||||
|
properties:
|
||||||
|
receipts:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Receipt"
|
||||||
|
SignupRequest:
|
||||||
|
type: object
|
||||||
|
required: [username, password]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
LoginRequest:
|
||||||
|
type: object
|
||||||
|
required: [username, password]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
AuthUserResponse:
|
||||||
|
type: object
|
||||||
|
required: [username, role]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
type: string
|
||||||
|
expires_at:
|
||||||
|
type: string
|
||||||
|
SessionResponse:
|
||||||
|
type: object
|
||||||
|
required: [valid]
|
||||||
|
properties:
|
||||||
|
valid:
|
||||||
|
type: boolean
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
type: string
|
||||||
|
expires_at:
|
||||||
|
type: string
|
||||||
|
CreateUserRequest:
|
||||||
|
type: object
|
||||||
|
required: [username, password, role]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
role:
|
||||||
|
type: string
|
||||||
|
enum: [user, admin]
|
||||||
|
tags:
|
||||||
|
- name: timestamping
|
||||||
|
description: Digests-only stamp, verify, and hash history
|
||||||
|
- name: auth
|
||||||
|
description: VeraeTime-direct account and session operations
|
||||||
358
site/ways.html
Normal file
358
site/ways.html
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Ways to use Verae timestamps</title>
|
||||||
|
<meta name="description" content="Ways to use Verae timestamps: AI MCP, browser, macOS direct download (notarized), TestFlight, Windows GUI, CLI, JavaScript, curl, explorer.">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="icon" href="assets/VeraeFullLogo.png">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--ink: oklch(0.21 0.020 310);
|
||||||
|
--ink-soft: oklch(0.42 0.018 310);
|
||||||
|
--ink-mute: oklch(0.60 0.014 310);
|
||||||
|
--paper: oklch(0.992 0.004 90);
|
||||||
|
--soft: oklch(0.972 0.008 85);
|
||||||
|
--hair: oklch(0.90 0.010 80);
|
||||||
|
--purple: oklch(0.32 0.110 310);
|
||||||
|
--purple-mid: oklch(0.42 0.130 312);
|
||||||
|
--purple-wash: oklch(0.96 0.020 312);
|
||||||
|
--gold: oklch(0.80 0.090 85);
|
||||||
|
--dark: oklch(0.19 0.022 312);
|
||||||
|
--ok: oklch(0.55 0.12 145);
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
color: var(--ink);
|
||||||
|
background: var(--paper);
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
a { color: var(--purple); }
|
||||||
|
header {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
max-width: 1100px; margin: 0 auto; padding: 28px 28px 0; flex-wrap: wrap; gap: 12px;
|
||||||
|
}
|
||||||
|
.brand img { height: 46px; width: auto; display: block; }
|
||||||
|
nav { display: flex; gap: 22px; font-size: 14px; font-weight: 600; flex-wrap: wrap; }
|
||||||
|
nav a { color: var(--ink-soft); text-decoration: none; }
|
||||||
|
nav a:hover, nav a.active { color: var(--purple); }
|
||||||
|
.hero { max-width: 1100px; margin: 0 auto; padding: 48px 28px 12px; }
|
||||||
|
.eyebrow {
|
||||||
|
font-size: 13px; font-weight: 700; letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase; color: var(--purple-mid);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-family: Fraunces, Georgia, serif; font-weight: 560;
|
||||||
|
font-size: clamp(34px, 5vw, 56px); line-height: 1.08;
|
||||||
|
letter-spacing: -0.03em; margin: 12px 0 18px; max-width: 20ch;
|
||||||
|
}
|
||||||
|
.lede { max-width: 46rem; font-size: 18px; color: var(--ink-soft); margin: 0; }
|
||||||
|
.gold { height: 3px; width: 72px; background: var(--gold); border: 0; margin: 28px 0; }
|
||||||
|
.wrap { max-width: 1100px; margin: 0 auto; padding: 12px 28px 80px; }
|
||||||
|
h2.section {
|
||||||
|
font-family: Fraunces, Georgia, serif; font-size: 30px; font-weight: 560; margin: 48px 0 8px;
|
||||||
|
}
|
||||||
|
.section-note { color: var(--ink-soft); max-width: 48rem; margin-top: 0; }
|
||||||
|
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; margin-top: 22px; }
|
||||||
|
.card {
|
||||||
|
background: white; border: 1px solid var(--hair); border-radius: 16px; padding: 22px;
|
||||||
|
}
|
||||||
|
.card .step {
|
||||||
|
font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--purple-mid);
|
||||||
|
}
|
||||||
|
.card h3 { font-size: 18px; margin: 6px 0 8px; }
|
||||||
|
.card p { margin: 0; color: var(--ink-soft); font-size: 15px; }
|
||||||
|
.card.featured { border-color: color-mix(in oklch, var(--purple) 35%, var(--hair)); background: linear-gradient(180deg, var(--purple-wash), white 48%); }
|
||||||
|
.btn-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 14px; }
|
||||||
|
.btn {
|
||||||
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
|
background: var(--purple); color: white; text-decoration: none; border: 0;
|
||||||
|
border-radius: 999px; padding: 12px 18px; font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
|
||||||
|
}
|
||||||
|
.btn.secondary { background: white; color: var(--purple); border: 1px solid var(--hair); }
|
||||||
|
.meta { font-size: 13px; color: var(--ink-mute); margin-top: 12px; }
|
||||||
|
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; }
|
||||||
|
pre {
|
||||||
|
background: var(--dark); color: oklch(0.95 0.01 90); border-radius: 14px;
|
||||||
|
padding: 16px 18px; overflow: auto;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.5; margin: 12px 0 0;
|
||||||
|
}
|
||||||
|
label.field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; font-weight: 600; color: var(--ink-soft); margin-top: 12px; max-width: 28rem; }
|
||||||
|
input[type=email], input[type=text], textarea {
|
||||||
|
font: inherit; font-weight: 500; color: var(--ink);
|
||||||
|
border: 1px solid var(--hair); border-radius: 10px; padding: 10px 12px; background: var(--soft);
|
||||||
|
}
|
||||||
|
textarea { min-height: 72px; resize: vertical; }
|
||||||
|
footer {
|
||||||
|
border-top: 1px solid var(--hair); padding: 28px; color: var(--ink-mute); font-size: 14px;
|
||||||
|
}
|
||||||
|
footer .inner { max-width: 1100px; margin: 0 auto; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
nav { gap: 14px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<a class="brand" href="https://www.verae.com/"><img src="assets/VeraeFullLogo.png" alt="Verae"></a>
|
||||||
|
<nav>
|
||||||
|
<a href="index.html">Install</a>
|
||||||
|
<a href="ways.html" class="active">Ways to use</a>
|
||||||
|
<a href="developers.html">Developers</a>
|
||||||
|
<a href="macos.html">macOS</a>
|
||||||
|
<a href="explorer.html">Explorer</a>
|
||||||
|
<a href="windows.html">Windows</a>
|
||||||
|
<a href="app.html">Browser app</a>
|
||||||
|
<a href="register.html">Register docs</a>
|
||||||
|
<a href="sample.html">Sample</a>
|
||||||
|
<a href="hasher.html">Hasher</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="hero">
|
||||||
|
<p class="eyebrow">Same MCP · many clients</p>
|
||||||
|
<h1>Ways to use Verae timestamps</h1>
|
||||||
|
<p class="lede">Hash locally; stamp digests only against the public Streamable HTTP endpoint. Start with <strong>AI MCP</strong>, then choose a browser, Mac/Windows UI, CLI, JS, or curl client. File bytes never upload.</p>
|
||||||
|
<hr class="gold">
|
||||||
|
</section>
|
||||||
|
<div class="wrap">
|
||||||
|
<section id="list">
|
||||||
|
<div class="grid">
|
||||||
|
<article class="card featured" id="ai-mcp">
|
||||||
|
<p class="step">1 · Start here</p>
|
||||||
|
<h3>AI MCP</h3>
|
||||||
|
<p>Point Claude.ai, ChatGPT, Grok, Claude Desktop, or Cursor at <code id="mcp-url">https://mcp.verae.ai/mcp</code>. The assistant calls <code>stamp</code> / <code>verify</code> / <code>hash_report</code>. First connect may open Verae browser login.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="index.html#connectors">Connectors by host</a>
|
||||||
|
<a class="btn secondary" href="index.html#connect">mcp.json snippet</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="browser">
|
||||||
|
<p class="step">2 · Browser</p>
|
||||||
|
<h3>Browser app</h3>
|
||||||
|
<p>Full Register / Verify client in the browser (WASM hash, auth defaults, CSV / JSON / PDF / text). Digests only.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="app.html">Open browser app</a>
|
||||||
|
<a class="btn secondary" href="register.html">Multi-doc register</a>
|
||||||
|
<a class="btn secondary" href="sample.html">MCP sample</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="explorer">
|
||||||
|
<p class="step">2 · Explorer</p>
|
||||||
|
<h3>Verify receipt or file hash</h3>
|
||||||
|
<p>Public lookup: paste a receipt CID, SHA-256, or drop a file (hashed in-browser). On-chain merkle opens in the <a href="https://explorer.verae.ai/">blockchain explorer</a>.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="explorer.html">Timestamp explorer</a>
|
||||||
|
<a class="btn secondary" href="https://explorer.verae.ai/" target="_blank" rel="noopener">Chain explorer</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card featured" id="mac-ui">
|
||||||
|
<p class="step">3 · UI · Mac</p>
|
||||||
|
<h3>macOS direct download</h3>
|
||||||
|
<p>Native SwiftUI <strong>Verae Timestamping</strong> — Developer ID signed, <strong>Apple-notarized</strong> universal zip. No TestFlight. Download → unzip → Open.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="macos.html">macOS download page</a>
|
||||||
|
<a class="btn secondary" href="/downloads/macos/VeraeTimestamping-macos-universal.zip">.app zip</a>
|
||||||
|
<a class="btn secondary" href="#testflight">TestFlight invite</a>
|
||||||
|
</div>
|
||||||
|
<p class="meta">Gatekeeper: Notarized Developer ID · macOS 14+ · quarantine clear only if a download flag still blocks Open.</p>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="windows-ui">
|
||||||
|
<p class="step">3 · UI · Windows</p>
|
||||||
|
<h3>Windows GUI</h3>
|
||||||
|
<p>Frozen amd64 EXEs — PySide6 GUI, CLI, optional hasher. SmartScreen warns (not code-signed); verify SHA-256 first.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="windows.html">Windows download page</a>
|
||||||
|
<a class="btn secondary" href="/downloads/windows/verae-timestamp-gui.exe">GUI EXE</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="cli">
|
||||||
|
<p class="step">4 · CLI</p>
|
||||||
|
<h3>Command line</h3>
|
||||||
|
<p>Official Python client: hash locally, stamp via MCP, write receipts under <code>~/.verae/receipts/</code>. On Windows use <code>verae-timestamp.exe</code>.</p>
|
||||||
|
<pre id="cli-snip">uvx verae-mcp-timestamping-client \
|
||||||
|
--url https://mcp.verae.ai/mcp \
|
||||||
|
--scope global \
|
||||||
|
./document.pdf</pre>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn secondary" href="index.html#apps">More CLI notes</a>
|
||||||
|
<a class="btn secondary" href="windows.html#cli">Windows CLI</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="js">
|
||||||
|
<p class="step">5 · JavaScript</p>
|
||||||
|
<h3>Embed with fetch</h3>
|
||||||
|
<p>Any web app: WASM/WebCrypto hash in-page, then <code>POST</code> Streamable HTTP JSON-RPC to <code>/mcp</code> (CORS <code>*</code>). Session id from <code>Mcp-Session-Id</code>.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="index.html#apps">JS snippet on Install</a>
|
||||||
|
<a class="btn secondary" href="app.html">See live client</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="curl">
|
||||||
|
<p class="step">6 · curl</p>
|
||||||
|
<h3>Raw JSON-RPC</h3>
|
||||||
|
<p><code>initialize</code> → <code>notifications/initialized</code> → <code>tools/call</code> (<code>stamp</code>, <code>verify</code>, <code>hash_report</code>). Include <code>Accept: application/json, text/event-stream</code>.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="index.html#apps">curl examples</a>
|
||||||
|
<a class="btn secondary" href="developers.html#curl-mcp">Developers curl</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card featured" id="application-client">
|
||||||
|
<p class="step">7 · Application Client</p>
|
||||||
|
<h3>Application Client / OpenAPI</h3>
|
||||||
|
<p>Non-AI apps: Python & TypeScript SDKs, digests-only OpenAPI, curl to VeraeTime (global) or MCP (local/shared). Logical SDK paths — not REST routes on this host.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="developers.html">Developers page</a>
|
||||||
|
<a class="btn secondary" href="openapi/application-client.yaml">OpenAPI YAML</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="card" id="hasher">
|
||||||
|
<p class="step">Also</p>
|
||||||
|
<h3>Local hasher · uvx server</h3>
|
||||||
|
<p>Download <code>verae-sha256</code> for your OS, or hash in-browser with WASM. Optional local MCP: <code>uvx verae-mcp-timestamping-server</code> and <code>… setup</code> for machine login.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn secondary" href="index.html#hasher">Get hasher</a>
|
||||||
|
<a class="btn secondary" href="hasher.html">WASM hasher</a>
|
||||||
|
<a class="btn secondary" href="index.html#register">Machine login</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="downloads">
|
||||||
|
<h2 class="section">Downloads hub</h2>
|
||||||
|
<p class="section-note">Stable artifact URLs on this host. macOS zip is Developer ID + notarized (not MAS).</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="explorer.html">Timestamp explorer</a>
|
||||||
|
<a class="btn" href="macos.html">macOS direct download</a>
|
||||||
|
<a class="btn" href="windows.html">Windows GUI + CLI</a>
|
||||||
|
<a class="btn secondary" href="/downloads/macos/SHA256SUMS">macOS SHA256SUMS</a>
|
||||||
|
<a class="btn secondary" href="/downloads/windows/SHA256SUMS">Windows SHA256SUMS</a>
|
||||||
|
<a class="btn secondary" href="/hasher/latest.json">Hasher latest.json</a>
|
||||||
|
<a class="btn secondary" href="#testflight">Mac TestFlight</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="macos-direct">
|
||||||
|
<h2 class="section">macOS direct download (no TestFlight)</h2>
|
||||||
|
<p class="section-note">Universal <strong>Verae Timestamping.app</strong> (v0.2.1 / build 7), signed <em>Developer ID Application: FlightLookup Inc.</em> and Apple-notarized with staple. Gatekeeper accepts as <em>Notarized Developer ID</em>.</p>
|
||||||
|
<div class="card" style="margin-top:18px">
|
||||||
|
<ol style="padding-left:1.2rem;margin:0;color:var(--ink-soft);font-size:15px;max-width:48rem">
|
||||||
|
<li style="margin:0.45rem 0"><strong>Download</strong> <a href="/downloads/macos/VeraeTimestamping-macos-universal.zip"><code>VeraeTimestamping-macos-universal.zip</code></a> (~546 KiB).</li>
|
||||||
|
<li style="margin:0.45rem 0"><strong>Unzip</strong> → drag the app to <code>/Applications</code> (optional).</li>
|
||||||
|
<li style="margin:0.45rem 0">If Gatekeeper still blocks a quarantined copy: right-click → <em>Open</em>, or run <code>xattr -dr com.apple.quarantine "/Applications/Verae Timestamping.app"</code>.</li>
|
||||||
|
<li style="margin:0.45rem 0"><strong>Open</strong> → first launch (MCP default <code>https://mcp.verae.ai/mcp</code>).</li>
|
||||||
|
</ol>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="macos.html">Full macOS instructions</a>
|
||||||
|
<a class="btn secondary" href="/downloads/macos/VeraeTimestamping-macos-universal.zip">Download zip</a>
|
||||||
|
<a class="btn secondary" href="/downloads/macos/SHA256SUMS">SHA256SUMS</a>
|
||||||
|
</div>
|
||||||
|
<p class="meta">CLI without the .app: <code>uv sync</code> then <code>uv run verae-timestamp …</code> in the client repo, or <code>uvx verae-mcp-timestamping-client</code> when published.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="testflight">
|
||||||
|
<h2 class="section">Request a macOS TestFlight invite</h2>
|
||||||
|
<p class="section-note">Optional App Store–style beta. Prefer the <a href="#macos-direct">direct notarized zip</a> if you do not want TestFlight. External testing still requires Apple Beta App Review — until that lands, invites are added manually for your Apple ID.</p>
|
||||||
|
<div class="card" style="margin-top:18px">
|
||||||
|
<h3 style="margin:0 0 8px;font-size:18px">Public join link</h3>
|
||||||
|
<p>When external Beta Review is approved, open:</p>
|
||||||
|
<p style="margin:10px 0"><a href="https://testflight.apple.com/join/dsHsyx2Z"><code>https://testflight.apple.com/join/dsHsyx2Z</code></a></p>
|
||||||
|
<p class="meta">If the link says the beta is full or unavailable, request an invite below.</p>
|
||||||
|
<div class="btn-row">
|
||||||
|
<a class="btn" href="https://testflight.apple.com/join/dsHsyx2Z">Open TestFlight join</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card" style="margin-top:18px">
|
||||||
|
<h3 style="margin:0 0 8px;font-size:18px">Request invite (Apple ID email)</h3>
|
||||||
|
<p>Submit the Apple ID email you use for TestFlight. The server adds you to the external testers group via App Store Connect and resends the invitation.</p>
|
||||||
|
<form id="tf-form">
|
||||||
|
<label class="field">Apple ID email
|
||||||
|
<input type="email" id="tf-email" required placeholder="you@example.com" autocomplete="email">
|
||||||
|
</label>
|
||||||
|
<label class="field">Optional note
|
||||||
|
<textarea id="tf-note" placeholder="Name, org, or why you need access"></textarea>
|
||||||
|
</label>
|
||||||
|
<div class="btn-row">
|
||||||
|
<button type="submit" class="btn" id="tf-submit">Request TestFlight invite</button>
|
||||||
|
<a class="btn secondary" href="mailto:marchon@gmail.com?subject=Verae%20Timestamping%20%E2%80%94%20macOS%20TestFlight%20invite%20request">Fallback: email marchon@gmail.com</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<p id="tf-status" class="meta" role="status" aria-live="polite" style="margin-top:14px"></p>
|
||||||
|
<p class="meta">Enrollment can succeed while the build is still <code>WAITING_FOR_BETA_REVIEW</code> — you may not see the app in TestFlight until Apple approves the beta.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<div class="inner">
|
||||||
|
<span>Verae timestamping · <a href="https://www.verae.com/">verae.com</a></span>
|
||||||
|
<span><a href="index.html">Install</a> · <a href="ways.html">Ways to use</a> · <a href="developers.html">Developers</a> · <a href="macos.html">macOS</a>
|
||||||
|
<a href="windows.html">Windows</a> · <a href="app.html">Browser app</a> · <a href="https://testflight.apple.com/join/dsHsyx2Z">TestFlight</a></span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var host = location.hostname || "mcp.verae.ai";
|
||||||
|
var mcpUrl = "https://" + host + "/mcp";
|
||||||
|
var el = document.getElementById("mcp-url");
|
||||||
|
if (el) el.textContent = mcpUrl;
|
||||||
|
var snip = document.getElementById("cli-snip");
|
||||||
|
if (snip) snip.textContent = snip.textContent.replaceAll("https://mcp.verae.ai/mcp", mcpUrl);
|
||||||
|
|
||||||
|
var form = document.getElementById("tf-form");
|
||||||
|
var status = document.getElementById("tf-status");
|
||||||
|
var submit = document.getElementById("tf-submit");
|
||||||
|
var endpoint = (location.origin && location.origin.indexOf("http") === 0)
|
||||||
|
? (location.origin + "/api/testflight-invite")
|
||||||
|
: "https://mcp.verae.ai/api/testflight-invite";
|
||||||
|
|
||||||
|
function setStatus(msg, ok) {
|
||||||
|
if (!status) return;
|
||||||
|
status.textContent = msg;
|
||||||
|
status.style.color = ok === true ? "var(--ok)" : (ok === false ? "oklch(0.5 0.16 25)" : "var(--ink-mute)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener("submit", async function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var email = (document.getElementById("tf-email").value || "").trim();
|
||||||
|
var note = (document.getElementById("tf-note").value || "").trim();
|
||||||
|
if (!email) { setStatus("Enter an Apple ID email.", false); return; }
|
||||||
|
if (submit) submit.disabled = true;
|
||||||
|
setStatus("Enrolling via App Store Connect…", null);
|
||||||
|
try {
|
||||||
|
var res = await fetch(endpoint, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json", "Accept": "application/json" },
|
||||||
|
body: JSON.stringify({ email: email, note: note })
|
||||||
|
});
|
||||||
|
var data = {};
|
||||||
|
try { data = await res.json(); } catch (_) {}
|
||||||
|
if (res.ok && data.ok) {
|
||||||
|
var msg = "Invite requested for " + email + ". Check TestFlight / email from Apple.";
|
||||||
|
if (data.beta_review_note) msg += " " + data.beta_review_note;
|
||||||
|
if (data.join_url) msg += " Public join: " + data.join_url;
|
||||||
|
setStatus(msg, true);
|
||||||
|
} else {
|
||||||
|
setStatus((data && data.message) || ("Enrollment failed (" + res.status + "). Use the mailto fallback or try again."), false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setStatus("Could not reach enrollment API. Use the mailto fallback to marchon@gmail.com.", false);
|
||||||
|
} finally {
|
||||||
|
if (submit) submit.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in a new issue