Furniture
Halden Oak Dining Table
€749
Furniture, kitchen and textiles, made to last and shipped across Europe — with a catalog open to verified AI shopping agents.
Hand-picked for the season.
Every AI agent that presents a credential at our catalog API — granted or blocked. Run the flow in the TSAI sandbox, then refresh.
| Time | Decision | Reason | Agent |
|---|---|---|---|
| 2026-06-18 17:47:32 UTC | ✗ denied | invalid | did:key:z6MkmbAQpXZbaYghjC… |
| 2026-06-18 17:39:29 UTC | ✗ denied | missing | — |
| 2026-06-18 17:33:34 UTC | ✓ granted | granted | did:key:z6MkmbAQpXZbaYghjC… |
| 2026-06-18 17:23:54 UTC | ✗ denied | invalid | did:key:z6Mkha4G2EDF1TmxRe… |
| 2026-06-18 17:23:31 UTC | ✗ denied | invalid | did:key:z6Mkgm9iCE3kiU6Ktm… |
| 2026-06-18 17:00:36 UTC | ✓ granted | granted | did:key:z6MktpLXFNGZuEQAa7… |
| 2026-06-18 16:55:27 UTC | ✗ denied | missing | — |
| 2026-06-18 16:09:11 UTC | ✗ denied | missing | — |
| 2026-06-18 16:07:55 UTC | ✗ denied | missing | — |
| 2026-06-18 15:20:35 UTC | ✗ denied | invalid | did:key:z6MkjrdFrN73wNH6H5… |
The whole TSAI check runs on your server: read the TSAI-Credential header, verify it in two steps, then grant or deny around your catalog. The table above is exactly this code logging every call.
// npm i jose agent-verification
import { decodeJwt, importJWK, jwtVerify } from "jose";
import { verifyOffline, resolveDid } from "agent-verification";
const SP_AUDIENCE = "did:web:sp.sandbox.tsai-test.trstd.com"; // this Service Provider's did:web
const TA_DID_DOC = "https://sandbox.tsai-test.trstd.com/tsai/.well-known/did.json"; // the Trust Authority
let taDoc; // verifyOffline needs the TA's DID document injected — fetch once.
const loadTaDoc = async () => (taDoc ??= await (await fetch(TA_DID_DOC)).json());
// grant/deny for the value of the incoming "TSAI-Credential" header.
async function checkTsai(vpJwt) {
if (!vpJwt) return { decision: "deny", reason: "missing" };
const { iss: agentDid, verifiableCredential: [vc] = [] } = decodeJwt(vpJwt);
if (!agentDid?.startsWith("did:key:") || !vc)
return { decision: "deny", reason: "malformed", agentDid };
// 1) Presentation signed by the agent, bound to us (audience), unexpired.
try {
const { publicKeyJwk } = (await resolveDid(agentDid)).verificationMethod[0];
await jwtVerify(vpJwt, await importJWK(publicKeyJwk, "EdDSA"),
{ audience: SP_AUDIENCE, clockTolerance: 30 });
} catch { return { decision: "deny", reason: "invalid", agentDid }; }
// 2) Enclosed credential really issued by the Trust Authority (offline),
// and belongs to this agent.
const r = await verifyOffline(vc, { didDocument: await loadTaDoc() });
if (!r.verified || r.credential.subject !== agentDid)
return { decision: "deny", reason: r.error?.code ?? "invalid", agentDid };
return { decision: "grant", reason: "granted", agentDid, tsai: r.credential };
}
// Gate your catalog + log every attempt (that is the table above).
app.get("/catalog", async (req, res) => {
const result = await checkTsai(req.header("TSAI-Credential"));
console.log("[tsai]", new Date().toISOString(),
result.decision, result.reason, result.agentDid ?? "-");
if (result.decision !== "grant") return res.status(403).json(result);
res.json({ items: /* your catalog */ [] });
});