Demo storefront for the TSAI Trust Authority · Acme Home & Garden is fictional — no real products or orders.
Acme Home & Garden
New season

Considered pieces for everyday living.

Furniture, kitchen and textiles, made to last and shipped across Europe — with a catalog open to verified AI shopping agents.

Free EU shipping over €7530-day returnsSecure checkoutOpen to verified AI agents

Featured

Hand-picked for the season.

Furniture

Halden Oak Dining Table

★ 4.9 · 100+ sold
€749
Bedroom

Brae Linen Duvet Set

★ 4.7 · 100+ sold
€89
Kitchen

Fennlow Cast-Iron Oven

★ 4.8 · 100+ sold
€119
Lighting

Aubin Pendant Light

★ 4.6 · 100+ sold
€59
Garden

Terra Planter Trio

★ 4.5 · 100+ sold
€39
Living

Mireval Wool Throw

★ 4.9 · 100+ sold
€69

Catalog access

Every AI agent that presents a credential at our catalog API — granted or blocked. Run the flow in the TSAI sandbox, then refresh.

Latest attempts · last 10
TimeDecisionReasonAgent
2026-06-18 17:47:32 UTC✗ deniedinvaliddid:key:z6MkmbAQpXZbaYghjC…
2026-06-18 17:39:29 UTC✗ deniedmissing
2026-06-18 17:33:34 UTC✓ grantedgranteddid:key:z6MkmbAQpXZbaYghjC…
2026-06-18 17:23:54 UTC✗ deniedinvaliddid:key:z6Mkha4G2EDF1TmxRe…
2026-06-18 17:23:31 UTC✗ deniedinvaliddid:key:z6Mkgm9iCE3kiU6Ktm…
2026-06-18 17:00:36 UTC✓ grantedgranteddid:key:z6MktpLXFNGZuEQAa7…
2026-06-18 16:55:27 UTC✗ deniedmissing
2026-06-18 16:09:11 UTC✗ deniedmissing
2026-06-18 16:07:55 UTC✗ deniedmissing
2026-06-18 15:20:35 UTC✗ deniedinvaliddid:key:z6MkjrdFrN73wNH6H5…

Add this check to your site

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 */ [] });
});