FAQ
Answers to the questions we hear most.
Why is /ingest returning 401 Unauthorized?
A 401 from /ingest has two causes, and the response names which one in its reason field. key_not_registered means your Ed25519 envelope public key isn't on file. key_not_yet_valid means the key is registered but the event is dated before that key existed — a key only covers events from its creation onwards, which is what stops anyone signing back-dated evidence. That one bites when you back-fill older logs with a key you generated today; re-send with current timestamps, or generate the key before the period you intend to capture. The wrapper signs every event with your customer-held Ed25519 key, and the backend refuses unverifiable events to keep the chain honest. Since SDK 1.0.1 the failure surfaces earlier: init() probes key registration up front and raises WytnessInitError before any event is sent — so a raw /ingest 401 usually means a direct (non-SDK) send or an old SDK. Either way the fix is the same.
To fix it (one-time, ~30 seconds):
- Open the dashboard Keys page.
- Click Generate on each of the Signing, Encryption, and HMAC tabs. The public halves auto-register against your org; download each private half.
- Copy the displayed env values from the Onboarding "Instrument" step into your secrets manager (Azure Key Vault, AWS, Vercel, k8s, etc.) — or a
.envfile for local dev. Subsequent events are accepted.
Wytness never sees the private halves — both Ed25519 (envelope) and X25519 (PII reveal) are generated in the browser with crypto.getRandomValues() + TweetNaCl, and only the public halves leave your machine.
Is my data safe?
The wrapper pseudonymises PII before the event leaves your runtime, so Wytness holds tokens rather than the values behind them. Emails, phone numbers, payment cards, SSNs and AU TFNs are detected automatically; names, addresses and other free text are covered once you declare those fields in pii_fields — the regexes cannot spot a name, so that declaration is what closes the gap. Every event is signed with your Ed25519 key, so Wytness cannot fabricate or modify entries on your behalf. In transit, all events go over HTTPS (TLS 1.3). At rest, events are stored in a per-org analytics partition with column encryption, and the raw CloudEvents envelopes are sealed in a per-org append-only Azure Blob archive with long-term (7-year) retention and a soft-delete recovery window.
On the Business tier, the Blob archive lives in your Azure Storage account — bring-your-own-storage, so any immutability policy is yours to set on a container you control; an AWS S3 adapter is on the roadmap. Even the encrypted-at-rest copy doesn't sit on Wytness-controlled infrastructure.
How does PII protection work?
Two mechanisms run inside the wrapper before egress: regex detection for structured PII (emails, phones, SSN, AU TFN, credit cards) and field-level declaration for everything else via pii_fields / piiFields. Both replace the value with a deterministic HMAC-SHA256 pseudonym:
Email addresses → EMAIL_3c866e6fUS SSN (xxx-xx-xxxx) → SSN_a1b2c3d4AU TFN (xxx-xxx-xxx) → TFN_7d2e91faCredit cards (xxxx-xxxx-xxxx-xxxx) → CARD_b8f4e210Phone numbers → PHONE_9a3c5f78Declared pii_fields paths → PII_6a7b8c9dThe pseudonym is derived from HMAC-SHA256 of the original value using your secret, so the same value always produces the same token — you can correlate events involving the same person without storing their actual data.
An encrypted token map is attached to each event, mapping pseudonyms back to originals, encrypted with ChaCha20-Poly1305 + a per-event ephemeral X25519 keypair. Only the holder of your X25519 private key can decrypt it. Wytness cannot. See the full PII Protection guide for setup.
How do I reveal pseudonymised PII?
Go to Keys → PII Reveal Key in the dashboard and paste your X25519 private key (the base64-encoded 32-byte key you downloaded when you clicked Generate on the PII Encryption Key card).
Once loaded, pseudonymised events across the Events and Sessions pages show a reveal toggle. Click it to see the original values, highlighted in amber. The key is held in browser memory only — never sent to Wytness servers, never persisted to disk. Closing the tab clears the key.
How do I rotate my API key?
Go to the Keys page in your dashboard. You can have multiple WYTNESS_API_KEY values active at the same time, which makes rotation seamless:
- Create a new API key on the Keys page.
- Update the
WYTNESS_API_KEYenvironment variable (in your secrets manager, or your local.env) to the new value. - Deploy the updated agent.
- Verify events flow with the new key (check the dashboard Events page).
- Revoke the old key on the Keys page.
During the transition, both keys are valid. There's no downtime.
What's the difference between the signing key and the API key?
They serve different purposes:
- API key (
WYTNESS_API_KEY, prefixwyt_api_live_…) — server-issued. Authenticates your wrapper SDK with the Wytness backend. Sent as the HTTP Bearer token. - Signing key (
WYTNESS_SIGNING_KEY, base64 Ed25519 private key) — browser-generated. Signs every event's canonical-shape payload. The private half stays on your machine; only the public half is registered with Wytness.
Rotate them independently. The API key is managed in the dashboard. The signing keypair is generated by clicking Generate on the Signing Key card on the Keys page — Wytness never sees the private key.
Does it work with LangChain, CrewAI, or other frameworks?
Yes — wherever AGT can run. AGT-Python 4.1.0 ships 12 first-party framework integrations (LangChain, LangGraph, CrewAI, Haystack, MCP, Flowise, Langflow, Swarm, A2A, AI Card, plus HTTP and Django middleware). AGT-TS ships GenericFrameworkAdapter only — you write one adapter method against your framework's tool-call lifecycle. Either way, the wrapper forwards every audit entry AGT's AuditLog chains. See the framework integrations guide.
What happens if the network is down?
Failed POSTs land in a local JSONL dead-letter file — one CloudEvents envelope per line, still signed and PII-pseudonymised. Replay by POSTing the file back to /ingest once connectivity returns.
Does it slow down my agent?
Negligible. The HTTP POST is non-blocking — events are queued, batched (default 100 entries or 5 seconds, whichever first), and flushed off the hot path. Signing an event with Ed25519 takes microseconds. PII regex + HMAC pseudonymisation runs in the same order.
Can I run multiple agents under one account?
Yes. Each agent gets its own AGT DID (the agent_id field on every entry). All agents under the same org share one Wytness API key and one dashboard. The dashboard filters by agent_id so you can view each agent independently or see them all together.
What happens if I exceed my tier's caps?
Paid orgs are not hard-stopped at the cap. Events keep ingesting, agents keep being recorded, and overage accrues at the per-event and per-agent rate published on the pricing page. Once the accumulator crosses 25% of your plan price, a Stripe off-session charge fires for the accumulated amount and the accumulator resets — so you'd see a handful of small mid-cycle debits with statement descriptor WYTNESS OVERAGE rather than a single invoice-end shock. Any sub-threshold remainder left when your cycle renews is collected in one final debit at renewal, so every cycle starts at zero. Full mechanics live in the Billing & Metered Overage guide.
Trial orgs are different: with no card on file, trials retain the original hard 402 Payment Required cap. Add a card and convert to a paid plan to switch to the metered flow.
What if a card payment fails?
You get a 48-hour grace window. Inside it, ingestion continues, an undismissable banner appears in the dashboard, and escalating emails go to your billing contact on hours 0, 6, 18, and 36 while Stripe retries. If the 48 hours close with no successful charge, ingestion pauses for the org — new POSTs return 402 Payment Required until the card is fixed. Nothing is deleted; the chain isn't broken; ingestion resumes the moment the payment clears.
How do I see live usage and accrued overage?
The dashboard billing page is live — events and active agents update within seconds of each ingest, alongside accrued overage in dollars and the next-charge threshold. For "what if" estimates against any tier and any volume, the public overage calculator does the same math without signing in.
How long is data retained?
Retention is set per tier. Starter: 30 days hot. Growth: 90 days hot. Business: 7-year retention while subscribed (on cancellation, your history is handed over as signed Evidence Packs), with the cold-tier archive landing in your Azure Blob bucket in your tenancy (BYOS standard at Business+). Enterprise: custom retention, BYOS standard, sovereign region selection. See the Pricing page for the canonical per-tier breakdown.
How do I install the SDK?
Two packages, same shape on both runtimes: pip install wytness-ai (Python — imports as import wytness_ai) or npm install @wytness/ai (TypeScript). Both pull Microsoft AGT in automatically — no extras to remember.
- Wire AGT into your framework using AGT's docs.
- Call
wytness_ai.init()once at process start. AGT's audit log is auto-wired into the Wytness envelope path. - Generate keys on the dashboard Keys page (the Signing, Encryption, and HMAC tabs) — Ed25519 signing pair plus the X25519 + HMAC pair for PII.
See the Python quickstart or TypeScript quickstart for the end-to-end shape, and the changelog for release history.
Where are your legal and compliance documents?
Everything is in the Trust Centre:
Is there a status page?
Yes. Check System Status for real-time health of all platform services. The footer on every page also shows a live status indicator.
Ready to audit your AI agents?
Start recording