hosted/ifttt-src/src/pages/api/index.astro
2025-12-31 21:32:46 +00:00

252 lines
9.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
import Hero from "@/components/blocks/hero-1.astro";
import { Button } from "@/components/ui/button";
import { Icon } from "@/components/ui/icon";
import { Section, SectionContent, SectionGrid, SectionProse } from "@/components/ui/section";
import { Tile, TileContent, TileDescription, TileTitle } from "@/components/ui/tile";
import BaseLayout from "@/layouts/BaseLayout.astro";
---
<BaseLayout
title="IF.Trace — API"
description="Upload a file, get a SHA256, and receive a public receipt URL. Includes code examples and a live test page."
>
<Hero
link={{ text: "Back to home", href: "/", icon: "arrow-left" }}
links={[
{ text: "Open console", href: "/console/login", icon: "lock" },
{ text: "Read the whitepaper", href: "/whitepaper/", icon: "file-text" },
]}
image={{ src: "/assets/iftrace-diagram.svg", alt: "Upload → hash → receipt → share (example)" }}
>
<p>API</p>
<h1>Upload a file. Get a receipt.</h1>
<p>
This is the practical page. Copy/paste the examples, run a real request, and share the receipt URL with a reviewer.
</p>
</Hero>
<Section aria-label="Quickstart">
<SectionContent class="items-center">
<SectionProse class="text-center">
<p>Quickstart</p>
<h2>Three steps.</h2>
<p>1) Login. 2) Create an API key. 3) Upload a file to <code>/api/v1/traces</code>.</p>
</SectionProse>
</SectionContent>
<SectionGrid class="@3xl:grid-cols-3">
<Tile variant="floating">
<TileContent>
<TileTitle class="text-xl">1) Console</TileTitle>
<TileDescription>Login and create an API key for your organization.</TileDescription>
<div class="mt-4 flex flex-wrap gap-2">
<Button size="sm" href="/console/login">
<Icon name="lock" />
Login
</Button>
<Button size="sm" variant="outline" href="/console/api-keys">
<Icon name="key" />
API keys
</Button>
</div>
</TileContent>
</Tile>
<Tile variant="floating">
<TileContent>
<TileTitle class="text-xl">2) Upload</TileTitle>
<TileDescription>POST a file to <code>/api/v1/traces</code>.</TileDescription>
<pre class="mt-4 overflow-auto rounded-lg bg-muted p-4 text-xs leading-relaxed text-foreground">curl -fsS -X POST \\
-H 'X-API-Key: &lt;your_key&gt;' \\
-F 'file=@./document.pdf' \\
-F 'expected_sha256=&lt;optional_expected_sha256&gt;' \\
https://infrafabric.io/api/v1/traces</pre>
</TileContent>
</Tile>
<Tile variant="floating">
<TileContent>
<TileTitle class="text-xl">3) Share</TileTitle>
<TileDescription>Send the receipt URL to the reviewer. No login required.</TileDescription>
<pre class="mt-4 overflow-auto rounded-lg bg-muted p-4 text-xs leading-relaxed text-foreground"># Response includes:
receipt_url: https://infrafabric.io/api/v1/public/receipt/&lt;public_id&gt;</pre>
</TileContent>
</Tile>
</SectionGrid>
</Section>
<Section variant="floating" aria-label="Live test">
<SectionContent class="items-center">
<SectionProse class="text-center">
<p>Live test</p>
<h2>Try an upload right now.</h2>
<p>Paste your API key, pick a file, optionally provide an expected SHA256, and run the call.</p>
</SectionProse>
<div class="mt-8 w-full max-w-4xl rounded-xl border bg-card p-6 text-card-foreground">
<div class="@3xl:grid @3xl:grid-cols-2 @3xl:gap-6">
<form id="iftrace-upload" class="space-y-4">
<div>
<div class="text-sm font-semibold">API key</div>
<input
id="apiKey"
class="mt-2 w-full rounded-lg border bg-muted px-3 py-2 text-sm text-foreground"
placeholder="iftr_...."
autocomplete="off"
/>
</div>
<div>
<div class="text-sm font-semibold">File</div>
<input id="file" type="file" class="mt-2 w-full text-sm" />
</div>
<div>
<div class="text-sm font-semibold">Expected SHA256 (optional)</div>
<input
id="expected"
class="mt-2 w-full rounded-lg border bg-muted px-3 py-2 text-sm text-foreground"
placeholder="64 hex characters"
autocomplete="off"
/>
</div>
<Button type="submit" class="w-full">
<Icon name="upload" />
Upload and verify
</Button>
<p class="text-xs text-white/60">
This endpoint returns <code>verified</code> only if you provide <code>expected_sha256</code>. Otherwise it returns the computed hash.
</p>
</form>
<div>
<div class="text-sm font-semibold">Result</div>
<pre
id="result"
class="mt-2 min-h-[220px] overflow-auto rounded-lg bg-muted p-4 text-xs leading-relaxed text-foreground"
>{"{}"}</pre>
<div id="receiptWrap" class="mt-3 hidden">
<a id="receiptUrl" class="text-sm text-primary hover:underline" href="#" target="_blank" rel="noreferrer"
>Open public receipt</a
>
</div>
</div>
</div>
</div>
<script is:inline>
function qs(id) {
return document.getElementById(id);
}
async function runUpload(ev) {
ev.preventDefault();
const apiKey = (qs("apiKey").value || "").trim();
const fileEl = qs("file");
const expected = (qs("expected").value || "").trim();
const out = qs("result");
const receiptWrap = qs("receiptWrap");
const receiptUrl = qs("receiptUrl");
receiptWrap.classList.add("hidden");
receiptUrl.href = "#";
if (!apiKey) {
out.textContent = JSON.stringify({ error: "Missing API key" }, null, 2);
return;
}
if (!fileEl.files || fileEl.files.length === 0) {
out.textContent = JSON.stringify({ error: "Pick a file" }, null, 2);
return;
}
const fd = new FormData();
fd.append("file", fileEl.files[0]);
if (expected) fd.append("expected_sha256", expected);
out.textContent = "Uploading…";
try {
const res = await fetch("/api/v1/traces", {
method: "POST",
headers: { "X-API-Key": apiKey },
body: fd,
});
const body = await res.json().catch(() => ({}));
out.textContent = JSON.stringify(body, null, 2);
if (body && body.receipt_url) {
receiptUrl.href = body.receipt_url;
receiptWrap.classList.remove("hidden");
}
} catch (e) {
out.textContent = JSON.stringify({ error: String(e || "Request failed") }, null, 2);
}
}
const form = document.getElementById("iftrace-upload");
if (form) form.addEventListener("submit", runUpload);
</script>
</SectionContent>
</Section>
<Section aria-label="Code examples">
<SectionContent class="items-center">
<SectionProse class="text-center">
<p>Examples</p>
<h2>Copy/paste for common platforms.</h2>
</SectionProse>
<SectionGrid class="@3xl:grid-cols-2">
<Tile variant="floating">
<TileContent>
<TileTitle class="text-xl">Python (requests)</TileTitle>
<pre class="mt-3 overflow-auto rounded-lg bg-muted p-4 text-xs leading-relaxed text-foreground">import requests
API_KEY = "iftr_..."
with open("document.pdf", "rb") as f:
res = requests.post(
"https://infrafabric.io/api/v1/traces",
headers=&#123;"X-API-Key": API_KEY&#125;,
files=&#123;"file": ("document.pdf", f, "application/pdf")&#125;,
data=&#123;"expected_sha256": ""&#125;, # optional
timeout=60,
)
print(res.status_code)
print(res.json())</pre>
</TileContent>
</Tile>
<Tile variant="floating">
<TileContent>
<TileTitle class="text-xl">Node.js (fetch)</TileTitle>
<pre class="mt-3 overflow-auto rounded-lg bg-muted p-4 text-xs leading-relaxed text-foreground">import fs from "node:fs";
const apiKey = "iftr_...";
const fd = new FormData();
fd.append("file", new Blob([fs.readFileSync("document.pdf")]), "document.pdf");
// fd.append("expected_sha256", ""); // optional
const res = await fetch("https://infrafabric.io/api/v1/traces", &#123;
method: "POST",
headers: &#123; "X-API-Key": apiKey &#125;,
body: fd,
&#125;);
console.log(res.status);
console.log(await res.json());</pre>
</TileContent>
</Tile>
</SectionGrid>
</SectionContent>
</Section>
<Section aria-label="Meaning of verified">
<SectionContent class="items-center">
<SectionProse class="text-center">
<p>Meaning</p>
<h2>Integrity, not interpretation.</h2>
<p>
“Verified” means the computed hash matched an expected hash you provided.
It does not mean “true”, “compliant”, or “approved”.
</p>
</SectionProse>
</SectionContent>
</Section>
</BaseLayout>