Skip to main content
Auditors, compliance officers, and disputes teams use this layer to answer one question: “Why did this transaction get this decision, and can we prove no one tampered with that answer?” What changes in your operation: evidence of a control goes from “let me pull logs from N systems and reconcile timestamps” to “here is the immutable record, cryptographically chained, showing that this transaction got this decision because this specific rule fired at this moment.” That shift is the whole point. Trade-off to be honest about: there is no “delete” or “edit” on audit records — by design. A TRUNCATE trigger at the database level blocks bulk deletion; each record’s SHA-256 hash includes the previous record’s hash, so removing or re-dating a record breaks the chain everywhere downstream. If you need to remove a record for legal reasons (such as GDPR right-to-be-forgotten on PII), the answer is data minimization upfront, not retroactive editing.
Who is this guide for? Compliance officers and auditors checking what Tracer guarantees, disputes teams looking up validation history, and developers building reports against the audit endpoints. The compliance overview and retention sections assume zero API knowledge; the query and verify sections assume basic REST.
Tracer maintains a complete, immutable of all validation decisions. This guide explains how the audit system works and how to query validation history for compliance reporting.

Compliance overview


Tracer is designed to meet the audit requirements of financial regulations including:

Audit trail architecture


Tracer records every validation decision with full context for compliance and investigation.

What gets recorded

Every validation creates an immutable audit record containing:
Audit events are deduplicated for transaction validations. If a validation request is retried with the same requestId, only the first audit event is stored. This ensures the audit trail reflects unique business events, not API retry patterns.

Immutability and hash chain

Audit records are write-once and cryptographically chained:
  • Records cannot be modified after creation.
  • The audit table is protected at the database level: a TRUNCATE trigger blocks bulk deletion.
  • Each record stores a SHA-256 hash computed over the record’s identity, timestamp, actor, and the previous record’s hash, forming an append-only chain. Removing, re-ordering, or re-dating a record makes every later record fail verification.
  • A pg_advisory_xact_lock serializes hash-chain writes to keep the order stable under concurrent inserts.
You can verify the chain at any time using GET /v1/audit-events/{id}/verify, which returns:
The check covers the chain from its first record up to and including the record you name. When every hash still matches, isValid is true and message confirms it. When a record no longer matches its stored hash, isValid is false and message reports tampering. This is the cryptographic basis for SOX/GLBA tamper-evidence guarantees. On a failed check, firstInvalidId carries an internal sequence number for the diverging record. It is not an audit-event id, so it is not a value you can pass to GET /v1/audit-events/{id}.
The audit trail is designed for compliance audits. You can reconstruct exactly what happened for any validation, even years later, and prove that the records were not modified after the fact.

Data retention


Tracer retains data according to regulatory requirements and operational needs.

Retention periods

Compliance considerations

  • SOX requirement: Maintain records for 7 years from the date of the audit report
  • GLBA requirement: Retain records demonstrating compliance with privacy rules
  • Data export: Records can be exported for external audit systems

Querying validation history


Use the GET /v1/validations endpoint to query historical validations.

Basic query

Returns validations in cursor-paginated reverse chronological order.
A query with no dates covers the last 90 days, not the full retention period. Tracer applies that default window only when both start_date and end_date are absent. Send either one — or both — to query an older range: with only start_date, the range runs forward from that date with no end; with only end_date, it runs backward from that date with no start.

Filtered query

Available filters

Date format requirement

Date parameters must use RFC3339 format with mandatory timezone. Date-only formats are rejected.
Valid:
Invalid:

Pagination

Results use cursor-based pagination. The response includes nextCursor and hasMore fields to navigate through results.
When using cursor pagination, sort_by and sort_order are fixed from the original query.

Sorting


Getting validation details


Retrieve complete details for a specific validation using GET /v1/validations/{id}. The response contains everything needed to understand a validation decision:
  • Request snapshot: The complete input payload as received
  • Response snapshot: Full response including decision and reason
  • Evaluated rules: All rules that were checked
  • Matched rules: Rules that triggered (if any)
  • Limit details: Usage information for checked limits
  • Timestamps: When the validation occurred and processing time

Querying audit events


Beyond validation records, Tracer also exposes a generic audit event log via GET /v1/audit-events. This is the only way to see lifecycle changes for rules and limits — who created, updated, activated, deactivated, drafted, or deleted them.

Event types

Reservation events appear in the log but no filter selects them: event_type, action, and resource_type accept only the values listed in the table below, and a reservation value in any of them is rejected with error 0009. To read reservation events, query by date range and page through the results.

Filters

GET /v1/audit-events accepts the same date-range and scope filters as GET /v1/validations, plus filters tailored to lifecycle events:

Use cases

  • Who activated this rule? GET /v1/audit-events?resource_type=rule&resource_id={ruleId}&action=ACTIVATE
  • All rule changes last week: GET /v1/audit-events?resource_type=rule&start_date=...&end_date=...
  • All limit deletions in 2026: GET /v1/audit-events?resource_type=limit&action=DELETE&start_date=2026-01-01T00:00:00Z

Single event detail

Use GET /v1/audit-events/{id} to retrieve a specific audit record, including the snapshot of state at the time of the event.

Compliance reporting scenarios


Common queries for audit and compliance reporting.

Scenario 1: Audit investigation

“Why was this transaction denied on January 15th?”
The response shows the exact request received, all rules evaluated, which rule or limit caused the denial, and the timestamp.

Scenario 2: Monthly compliance report

“Show all denied transactions for corporate accounts in January”

Scenario 3: Rule effectiveness analysis

“Which transactions were denied by a specific fraud rule?”

Scenario 4: Limit utilization review

“Which transactions exceeded spending limits this month?”

Best practices for compliance


Recommendations for maintaining audit readiness.

Record keeping

  • Store validation IDs in your transaction records for easy cross-reference
  • Log the requestId you send to Tracer for correlation
  • Export regularly if you need records in external audit systems
Common pitfalls when reading the audit trail:
  • “I can see the validation but the rule that fired was already deleted.” Deleted rules are soft-deleted — the row stays in the database, but it doesn’t appear in GET /v1/rules. To investigate, query GET /v1/audit-events?resource_type=rule&resource_id={ruleId} for the lifecycle of that rule, including its activations and the eventual delete.
  • “Two retries of the same requestId only produced one audit event.” This is by design (deduplication via idx_audit_events_validation_dedup). The audit trail reflects unique business events, not API retry patterns. If your retry produced a different decision, that’s worth investigating — Tracer should return the original cached response.
  • /verify says the chain is broken on a record I haven’t touched.” The chain links every record to the previous one, so a tamper or DB corruption anywhere makes everything downstream report invalid. Run /verify against progressively earlier records to bracket where the chain first breaks.
  • “My audit query came back empty for last year.” A query with no start_date and no end_date covers the last 90 days. Supply the range you want.

Audit preparation

  • Test queries before audit season to ensure you can retrieve needed data
  • Verify date ranges work correctly with your timezone requirements
  • Document your retention policy alignment with Tracer’s 7-year retention

Investigation workflow

When investigating a specific transaction:
  1. Find the validation ID from your transaction logs or Tracer history
  2. Retrieve full details using GET /v1/validations/
  3. Review the request snapshot to see what data was provided
  4. Check matched rules to understand why the decision was made
  5. Verify limit status if limits were involved

No-match behavior and audit


When a validation runs and no rule matches, Tracer returns a configured default decision instead of treating the empty match as an error. This is a per-request fallback, not an infrastructure resilience strategy. The decision is governed by the DEFAULT_DECISION_WHEN_NO_MATCH environment variable (default: ALLOW).
Set DEFAULT_DECISION_WHEN_NO_MATCH=DENY for fail-closed semantics in high-security deployments. The service logs a warning at startup if this remains at the default ALLOW.
Infrastructure failures (database down, cache stale, timeout) do not fall back to ALLOW — they surface as HTTP errors to the client and the original transaction has no audit record. Operators should monitor tracer_audit_persist_failures_total and the /readyz endpoint to detect these cases.

Quick reference


Key endpoints and retention information.

Endpoints

Retention summary