Vanzim

User Guide

A complete walkthrough of your dashboard, what every button does, and how to verify a log, step by step.

Before you start, one thing you need to understand clearly

Once your conversation data reaches Vanzim, we permanently remove specific sensitive details from it, before anything is stored anywhere. Here's everything that gets caught, on every plan:

  • Email addresses
  • Phone numbers
  • Credit card numbers

On the Pro plan specifically, two more categories are also caught:

  • Ages (written as “34 years old,” “yrs old,” or similar)
  • Dates (in formats like 03/14/2026)

Each one gets replaced with a tag, [REDACTED_EMAIL], [REDACTED_PHONE], [REDACTED_CARD], [REDACTED_AGE], [REDACTED_DATE]. This is permanent and irreversible, once replaced, the original value is gone from anything Vanzim ever writes anywhere.

Here's what this doesn't catch: names, physical addresses, insurance IDs, and any other identifier not on this exact list are not currently detected. Don't treat this as a complete, catch-all redaction system on its own.

Want us to catch something that isn't on this list yet? Email contact@vanzim.com and tell us what you need. If it genuinely helps our users, we'll build it.

If you might need the full, original, unredacted conversation later, for your own records, a support ticket, or any other reason, you must keep your own separate copy in your existing systems, your CRM, your support platform, wherever that conversation naturally lives on your side. Vanzim proves your scrubbed record hasn't changed since it was created, it is not meant to be your only copy of anything.

1. Getting your API key

Go to Configuration. Find the card titled “Generate/Rotate API Key.”

  • The first time you click this button, it generates your very first API key. Any later click, once you already have a key, means rotating instead, which instantly invalidates the old one.
  • Click “Confirm: Generate/Rotate Now” to proceed.
  • Your new key appears exactly once, in a box that says “Copy this now, it will never be shown again.” Copy it immediately and store it somewhere safe. Vanzim only ever stores a scrambled, one-way version of your key internally, never the real value.

If you ever need to rotate your key again later (for example, if you suspect it's been exposed), the exact same button and process applies. Rotating instantly breaks any system still using the old key. This means you must also update the actual key value wherever your own backend uses it, usually stored as an environment variable, like VANZIM_API_KEY, on your own server, not just here in the Vanzim dashboard. Rotating here alone doesn't update your backend automatically, that's a separate step you have to do yourself, right after rotating. If you also change any settings on the AWS side yourself, like rotating your AWS access keys, you need to come back here and update those in Configuration too, otherwise Vanzim will start failing to reach your bucket.

2. Connecting your AWS bucket

Still on the Configuration page, find the “AWS Configuration” card.

Fill in:

  • Bucket Name, the exact name of your S3 bucket.
  • AWS Region, choose from the dropdown (US East, US West, EU Ireland, EU Frankfurt, Asia Pacific Singapore, Asia Pacific Tokyo, Asia Pacific Sydney).
  • Access Key ID and Secret Access Key, credentials for an AWS IAM user you've created, scoped specifically to this one bucket only, not your whole AWS account.

Two more things are required before you can save at all:

  1. Check the box confirming you've enabled Object Lock (WORM storage) on your own bucket, on the AWS side, yourself. This is a checkbox where you're confirming something you've already done, not something Vanzim sets up for you.
  2. Choose a retention method, one of two options: your bucket uses a lifecycle rule to automatically delete objects after your chosen retention period (for GDPR data minimization), or you're relying on a separately documented retention policy instead.

Once both are filled in, click “Save AWS Credentials.” The moment you save, Vanzim independently checks your bucket directly with AWS, not just trusting the checkbox. You'll see one of two results right there: “AWS confirms: Object Lock enabled” (with the actual mode and retention period shown), or “AWS confirms: Object Lock is not currently enabled.” This isn't a separate step, it happens automatically the moment you save.

3. Choosing your scrubbing level

Still on Configuration, find the “PII Scrubbing” card.

  • Standard (available on every plan): redacts emails, phone numbers, and credit card numbers.
  • Advanced (Pro plan only): does everything Standard does, plus redacts ages and dates.

If you're on the Starter plan, this toggle is disabled, with a message pointing you to upgrade if you want Advanced mode.

If you're on Pro, toggling this either direction shows you a confirmation dialog first, explaining exactly what's about to change. This only ever affects new logs sent after you make the change, it never goes back and reprocesses anything already archived.

4. Sending your first log

Go to Configuration. If you haven't generated an API key yet, do that first, using the “Generate/Rotate API Key” button covered in step 1. Once you have a key, scroll down to the “Integration Snippet” card, where you'll find the same code shown below, ready to copy directly into your own backend.

ai-handler.js
// Reuse the SAME request_id if you retry this exact event after a
// failure. Only generate a NEW request_id for a genuinely new event,
// this is what guarantees idempotency and prevents duplicate logs.
//
// Placeholders to replace with your own values:
// - chatLog.text -> wherever your code stores the conversation text
// - errorTrace -> wherever your code captures error details
// - elapsedMs -> however long your AI call actually took, in ms
// - model: 'gpt-4o' -> accepts any string (claude-sonnet-5, gemini-2.5, etc.)
// - duration_ms: 1250 -> an example number, use your elapsed time

// ============================================
// Use this block where your AI responds successfully
// ============================================

await fetch('https://vanzim-worker.vanzim.workers.dev/v1/ingest', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.VANZIM_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    request_id: crypto.randomUUID(),
    raw_text: chatLog.text,
    event_type: 'chat_completed',
    metadata: {
      model: 'gpt-4o',
      duration_ms: 1250,
    },
  }),
}).catch((err) => {
  // If this specific request fails, don't just lose it. This next
  // line calls a function named saveLocallyForRetry, but that
  // function does NOT exist yet, you need to build it yourself.
  // Most people build this to run automatically, checking periodically
  // for saved, failed logs and resending them on its own, but it's
  // your choice, you could also just save them somewhere
  // and resend manually if you'd rather.
  saveLocallyForRetry(chatLog, err);
});


// ============================================
// Use this SEPARATE block where your AI call fails.
// This does not go after the block above, it goes in
// a completely different part of your code, your error handling.
// Recording both outcomes, success and failure, fits how compliance
// frameworks like Article 12 are generally understood, full
// traceability of what actually happened. 'model' is flexible here
// too, same as above.
// ============================================

await fetch('https://vanzim-worker.vanzim.workers.dev/v1/ingest', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${process.env.VANZIM_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    request_id: crypto.randomUUID(),
    raw_text: errorTrace,
    event_type: 'system_error',
    metadata: { model: 'gpt-4o', duration_ms: elapsedMs },
  }),
});

What each part of this code does:

  • The URL is Vanzim's live endpoint, every request goes here.
  • The Authorization header carries your API key, read from your own server's environment variable, VANZIM_API_KEY.
  • request_id is a fresh, random ID your own code generates for every single log. This ties everything together later, your dashboard, the ledger, and verification all reference this exact ID.
  • raw_text is the actual conversation content. Vanzim scrubs this before it goes anywhere.
  • event_type is a label you choose yourself, right here in your own code, it's not something you set anywhere in the Vanzim dashboard or in AWS, describing what kind of interaction this was. 'chat_completed' and 'system_error' are just example labels, not fixed values, you can use any text you want here.
  • metadata carries extra context, like which AI model was used and how long it took to respond.
  • chatLog and errorTrace are just placeholder names used in this example. Your own code will call these something else, whatever variables you're already using to hold your AI's response or your error details.
  • The first block handles your AI's success case, and includes a .catch() for fail-open protection, if this specific request fails, that catch block runs instead of losing the log. You need to write saveLocallyForRetry() yourself, it's shown as a comment, but nothing happens automatically, you have to build it.
  • The second block is separate, meant for your own error-handling code, where your AI call itself has failed. This block does not include the same catch protection, since it only fires in an already-failure scenario.
  • This code uses await, which only works inside a function marked async. This code fragment is meant to be dropped into an existing function you already have, not used as a standalone piece. If you're pasting it into a function that isn't already declared as async, add that keyword, or the code will fail with an error.
  • Something to keep in mind: .catch() only catches network-level failures, your request never reaching Vanzim at all. If your request does reach Vanzim but gets rejected, for example, hitting your 500-log Starter limit, that shows up as a normal response with an error status, not a network failure, so .catch() alone won't catch it. If you want to handle these cases too, check the response status after your fetch call completes, before assuming success.
  • There's a 2MB maximum size for each request. Most conversations fit comfortably within this, but if you're sending very long conversation histories, keep this limit in mind, requests over 2MB will fail.
  • The comment above mentions reusing the same request_id when retrying after a failure. The code shown doesn't demonstrate this directly, both blocks generate a fresh ID every time. In practice, if you're retrying the exact same event, save the request_id from your first attempt, and use that same value again instead of generating a new one.

5. Finding your logs

Go to your dashboard's main Ledger view. Every log you've sent appears here, in a table with six columns:

  • Request ID, matches the ID your own code generated when sending it.
  • Timestamp, when it was received, shown in UTC.
  • Event Type, whatever you labeled it (like “chat_completed”).
  • Status, one of four states: Pending (just received, not yet archived), Archived (successfully written to your AWS bucket), Retrying (a temporary upload issue, being automatically retried), or Failed.
  • S3 Path, a button labeled “Copy S3 Path.” Click it to copy the exact file location inside your own AWS bucket to your clipboard. This path is actually known and available from the moment the log is first received, not only once it reaches Archived status, the button is enabled as soon as a log exists at all. If you copy a path while a log still shows Pending or Retrying, though, the actual file may not have finished uploading to your bucket yet. Wait for Archived status before actually trying to download it.
  • Verify, opens the internal verification tool, covered next.

6. Verifying a log, right in your dashboard

This is the fastest way to check a specific log yourself.

  1. Find the log in your Ledger, click “Copy S3 Path” to get its exact location.
  2. Open the AWS Console (or use the AWS CLI), navigate to your bucket, and download the file at that exact path.
  3. Back in your dashboard, click “Verify” on that same log row.
  4. Drag the file you just downloaded into the dialog that opens, or click to browse for it.
  5. Vanzim reads the file, recomputes its hash right in your browser, and compares it against what was originally recorded.

This tool already knows the correct, original hash for the specific log row you clicked “Verify” on, and directly compares your freshly computed hash against it. If you accidentally drop a file from a different log, you won't see a specific “wrong file” warning, you'll simply see a Hash Mismatch, since a different file naturally produces a different hash.

You'll see one of two outcomes. Hash Verified means the file is authentic and hasn't been altered since creation. Hash Mismatch means something about the file has changed since it was first sealed.

Either way, two hash values are shown together for you to compare yourself: the one your browser just computed from the file you dropped in, and the original one Vanzim recorded when this log was first created, retrieved from your dashboard's Ledger.

7. Verifying a log publicly, for an auditor or anyone without a Vanzim account

This is the same underlying check, but doesn't require logging in at all, useful when someone outside your own team, a customer's lawyer, an auditor, a regulator, needs to check a file themselves without needing to trust your word, or Vanzim's.

  1. Get the same, exact file from your AWS bucket, the same way described above.
  2. Send that file to whoever needs to verify it, over email, a shared drive link, however you'd normally share a file with them. Or, if you're on a call together, you could screen-share while they do this step themselves in real time, that's what “verify it together” means, watching them independently check it, rather than just telling them it's fine.
  3. Go to your public verification page, at vanzim.com/verify.
  4. Drop the file in.
  5. The check happens right in their own browser, no login required at all.

8. One current limitation you should know about

Right now, both verification methods only handle one file at a time. If you need to check many logs, you'll need to verify them individually, one at a time, for now. Bulk verification is something we're actively working on, but it isn't available yet.

Questions

If anything here doesn't match what you're seeing, or you run into an issue not covered, reach out at contact@vanzim.com.