NEWVectors or files. Pick a path.Start →
    Operations
    7 min read
    Updated 2026-09-01

    How to Prove Who Changed a Configuration, When, and Why

    Governance reviews ask you to reconstruct a change: who made it, what the value was before and after, when, and why. This walks through doing that from an audit log, including the value-level diff, the caller-supplied reason, and an NDJSON export an auditor can keep.

    Audit
    Change Management
    Governance
    Compliance
    Observability
    Enterprise

    The Short Answer



    To prove who changed a configuration, you need four things recorded at write time and queryable afterwards: the actor's identity, a value-level before-and-after of the fields that moved, an ISO8601 timestamp, and a caller-supplied reason. Mixpeek records all four on every audited write and exposes them at GET /v1/organizations/audit/logs, filterable by resource, actor, action and time range, with an NDJSON export at /export for handing evidence to a reviewer. The part most systems miss is the WHY: it has to be captured from the caller at the moment of the change, because nothing downstream can reconstruct intent.

    Why "check the logs" usually fails a governance review



    Most platforms can tell you that a configuration changed. A review asks harder questions, and each one breaks a different common implementation.

    Who, specifically. A log line saying an API key made the change is not an identity. A reviewer wants a person, and an audit record has to carry the resolved name and email alongside the key that was used, or you are handing over a token and an alibi.

    What the value was before. "Retriever updated" is not a change record. Without the previous value you cannot show that a threshold moved from 0.7 to 0.4, which is usually the entire question.

    Why. This is the one that cannot be reconstructed later. Timestamps and diffs are recoverable from the system; intent only exists in the head of whoever made the change, and it has to be captured at that moment or lost.

    In a form they can keep. A reviewer wants an artifact, not a dashboard session. Paginated JSON in a UI is not evidence handoff.

    Steps to reconstruct a change



    1. Narrow to the resource. Call GET /v1/organizations/audit/logs with resource_type and resource_id to get every recorded event against that object, newest first. 2. Bound the window. Add start and end as ISO8601 timestamps to cover the period under review, which keeps the result set to the events a reviewer actually asked about. 3. Identify the actor. Each event carries actor_id, actor_type, actor_name, actor_email and actor_key_name, so you can name a person and the credential they used rather than one or the other. 4. Read the value-level diff. The changes field records what moved, field by field, which is what turns "it was updated" into "this threshold went from one value to another". 5. Read the reason. The reason field holds the caller-supplied WHY, captured from the X-Change-Reason request header when it was present on the write. 6. Export the evidence. Call GET /v1/organizations/audit/logs/export with the same filters to receive application/x-ndjson, one event per line, which a reviewer can archive and diff independently of your UI.
    # Every change to one retriever in the review window
    GET /v1/organizations/audit/logs?resource_type=retriever&resource_id=ret_1a7be6&start=2026-08-01T00:00:00Z&end=2026-09-01T00:00:00Z
    
    # The same slice, as NDJSON for the reviewer to keep
    GET /v1/organizations/audit/logs/export?resource_type=retriever&resource_id=ret_1a7be6&start=2026-08-01T00:00:00Z&end=2026-09-01T00:00:00Z

    What one audit record contains



    FieldWhat it answers
    audit_id, timestampWhich event, and when, as ISO8601
    resource_type, resource_idWhich object was touched
    action, statusWhat was attempted, and whether it succeeded
    actor_id, actor_typeWho, as the system sees them
    actor_name, actor_email, actor_key_nameWho, as a reviewer needs them: a person and the key used
    changesThe value-level before and after
    reasonThe caller-supplied WHY
    ip_address, user_agentWhere the request came from
    The pairing that matters is actor_email with actor_key_name. A shared service key with no resolved identity fails a review, and a name with no key cannot be tied to the request that carried it.

    Capturing the WHY at write time



    Send X-Change-Reason on the mutating request and it lands on the audit record as reason. It is worth wiring into whatever already makes changes on your behalf, because that is the only moment the intent exists:
    curl -X POST https://api.mixpeek.com/v1/retrievers \
      -H "Authorization: Bearer $MIXPEEK_API_KEY" \
      -H "X-Change-Reason: lowering recall threshold for the Q3 relevance test (TICKET-4192)" \
      -H "Content-Type: application/json" \
      -d '{ ... }'
    A reason that names a ticket is more useful than a reason that describes the edit, because the edit is already in changes and the ticket is what a reviewer follows next.

    Frequently Asked Questions



    What is the difference between an audit log and an application log?



    An application log records what the system did; an audit log records what a person or credential caused it to do, in a form meant to be read by someone who was not there. The practical difference is the fields. Application logs rarely carry a resolved human identity, almost never carry a before value, and never carry intent. An audit record is built so a reviewer can reconstruct a decision without asking anyone what happened.

    Which configuration surfaces are covered?



    Audit events are keyed by resource_type and resource_id, so filtering by resource is how you scope a review to a retriever, a collection, a bucket, a namespace, or a taxonomy. Query GET /v1/organizations/audit/logs without a resource filter to see the full set your organization has generated.

    How do I hand evidence to an auditor?



    Use GET /v1/organizations/audit/logs/export with the same filters as the list endpoint. It returns application/x-ndjson, one JSON object per line, which is append-friendly and diffable, and takes a max_events cap so a wide export cannot run away. NDJSON matters here because a reviewer can hold the file and re-check it later without access to your account.

    What happens if nobody sends a reason?



    The reason field is null and the rest of the record is unaffected. That is the honest failure mode, and it is why the header is worth wiring into automation rather than leaving to whoever remembers. A change with a full diff and no reason still proves what happened and cannot prove why.

    Does this replace SOC 2 or HIPAA certification?



    No. An audit trail is a control, not an attestation. It is the kind of evidence a reviewer asks for while assessing a control, and it is useful whether or not a certification exists. Mixpeek's current certification status is published at mixpeek.com/trust.

    Related



  1. Change data capture for a search index for keeping an index in step with a source of truth
  2. Security for how data is protected in transit and at rest
  3. Trust Center for current certification status
  4. Managed Mixpeek

    Put multimodal search to work

    Connect a bucket and Mixpeek runs the whole multimodal search pipeline for you: extraction, indexing, and search over your own objects. No models to wire up, nothing to host.

    Start with Managed
    MVS · bring your own

    Already have vectors?

    Keep your embeddings on your own cloud and run dense, sparse, and BM25 search directly on object storage. From $25/mo.

    Start with MVS

    Run this on your own data

    Point Mixpeek at the storage you already have and search your video, images, audio, and documents the way this guide describes. Build starts at $25/mo for up to 1M vectors.

    Search your own archiveRead Docs

    Related guides

    Compliance

    How Do You Detect and Redact PII in Images, Video, and Audio?

    Text redaction is a solved problem and media redaction is not. A face is PII, a voice is PII, and so is the licence plate reflected in a shop window behind your subject. This works through what counts as identifying in each modality, why detect-then-blur leaves the original recoverable, how redaction interacts with an embedding you already computed, the irreversibility test that separates real redaction from a visual effect, and how to verify a redaction rather than trust the pipeline that claims it.

    Read guide →
    Retrieval

    How Do You Delete Data From a Vector Index? Embeddings, Tombstones, and the Right to Be Forgotten

    Deleting the source file does not delete the data. An embedding is derived data that outlives its origin, and most vector indexes mark a deletion rather than removing it. This works through the four places a deleted item still lives, what an ANN index actually does when you call delete, why a soft-deleted record can be invisible to reads and still block a re-create, whether an embedding can be inverted back into the thing it described, and how to verify an erasure rather than trust the API's 200.

    Read guide →
    Search & Discovery

    How Do I Debug Bad Retrieval Results in RAG and Vector Search?

    Bad retrieval fails in one of five layers (corpus, embedding space, query, filters, or fusion) and each layer's failure masquerades as the one below it. A practical debugging methodology: the five-layer checklist, why raw similarity scores mislead, stage-boundary tracing with a real silent-decimation incident, and what a retrieval explain plan should contain.

    Read guide →