Documentation

Everything you need to integrate AuditKit into your application. Ship tamper-evident, tenant-scoped audit logs in minutes.

Quick Start

Install the SDK and send your first audit event in under 5 minutes.

1. Install

terminal
npm install @auditkit/sdk

2. Initialize

app.ts
import { AuditKit } from '@auditkit/sdk';

const audit = new AuditKit({
  apiKey: process.env.AUDITKIT_API_KEY!,
  // Optional: baseUrl for self-hosted
  // baseUrl: 'https://audit.yourcompany.com',
});

3. Log your first event

app.ts
await audit.log('document.updated', {
  actor: { id: 'user_123', name: 'Jane Doe', email: 'jane@acme.com' },
  target: { type: 'document', id: 'doc_456', name: 'Q4 Report' },
  tenantId: 'org_acme',
  metadata: { ip: '203.0.113.1', userAgent: 'Mozilla/5.0...' },
});

SDK Reference

The AuditKit class provides the following methods:

log(action, options)

Log a single audit event. Returns the created event with its hash.

await audit.log('user.signed_in', {
  actor: { id: 'user_123', name: 'Jane Doe' },
  tenantId: 'org_acme',
  severity: 'info', // 'info' | 'warn' | 'error' | 'critical'
});

logMany(events)

Bulk-log multiple audit events in a single request. More efficient for high-volume ingestion.

await audit.logMany([
  { action: 'file.uploaded', actor: { id: 'u1' }, tenantId: 'org_1' },
  { action: 'file.uploaded', actor: { id: 'u2' }, tenantId: 'org_1' },
]);

search(query)

Search audit events with filters. Supports full-text search, date ranges, and field filters.

const results = await audit.search({
  q: 'document.updated',
  tenantId: 'org_acme',
  actorId: 'user_123',
  from: '2025-01-01',
  to: '2025-12-31',
  limit: 50,
});

forTenant(tenantId)

Create a tenant-scoped client. All subsequent calls are automatically scoped to this tenant.

const tenantAudit = audit.forTenant('org_acme');
await tenantAudit.log('user.signed_in', {
  actor: { id: 'user_123' },
  // tenantId is automatically set
});

createViewerToken(tenantId, options?)

Generate a short-lived JWT token for the embeddable React viewer. Scoped to a single tenant.

const token = await audit.createViewerToken('org_acme', {
  expiresIn: '1h',
  filters: { actorId: 'user_123' }, // optional pre-filters
});

verifyChain(tenantId)

Verify the SHA-256 hash chain integrity for a tenant. Returns verification results.

const result = await audit.verifyChain('org_acme');
// { valid: true, eventsVerified: 15234, brokenLinks: [] }

flush()

Flush any buffered events. Call before process exit to ensure all events are sent.

await audit.flush();

close()

Flush pending events and close the client. Call on application shutdown.

await audit.close();

Framework Integrations

Next.js Middleware

Automatically capture authentication and route-level events.

middleware.ts
import { withAuditKit } from '@auditkit/sdk/next';

export default withAuditKit(
  async function middleware(request) {
    // Your existing middleware logic
  },
  {
    apiKey: process.env.AUDITKIT_API_KEY!,
    // Auto-capture sign-in/sign-out events
    captureAuth: true,
    // Auto-capture route access events
    captureRoutes: ['/api/admin/*', '/api/billing/*'],
  }
);

export const config = {
  matcher: ['/api/:path*', '/dashboard/:path*'],
};

Hono Middleware

Audit logging middleware for Hono applications.

server.ts
import { Hono } from 'hono';
import { auditkit } from '@auditkit/sdk/hono';

const app = new Hono();

app.use(
  '/api/*',
  auditkit({
    apiKey: process.env.AUDITKIT_API_KEY!,
    // Extract tenant from request context
    getTenantId: (c) => c.get('tenantId'),
    // Extract actor from request context
    getActor: (c) => ({
      id: c.get('userId'),
      name: c.get('userName'),
    }),
  })
);

Drizzle ORM Hooks

Automatically log database mutations as audit events.

db.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { withAuditKit } from '@auditkit/sdk/drizzle';

const db = withAuditKit(
  drizzle(pool),
  {
    apiKey: process.env.AUDITKIT_API_KEY!,
    // Which tables to audit
    tables: ['users', 'documents', 'permissions'],
    // Map table operations to action names
    actionPrefix: 'db',
    // e.g., db.users.insert, db.documents.update
  }
);

React Viewer

Drop-in embeddable audit log viewer for your customer-facing dashboard. Tenant-scoped with JWT authentication.

Installation

terminal
npm install @auditkit/react

Usage

audit-page.tsx
import { AuditLog } from '@auditkit/react';

export function AuditPage({ viewerToken }: { viewerToken: string }) {
  return (
    <AuditLog
      token={viewerToken}
      // Optional customization
      theme="dark"
      pageSize={25}
      showSearch={true}
      showExport={true}
      onEventClick={(event) => openAuditEvent(event)}
    />
  );
}

Server-side token generation

api/audit-token/route.ts
import { AuditKit } from '@auditkit/sdk';
import { NextResponse } from 'next/server';

const audit = new AuditKit({ apiKey: process.env.AUDITKIT_API_KEY! });

export async function GET(request: Request) {
  const tenantId = getTenantFromSession(request);
  const token = await audit.createViewerToken(tenantId, {
    expiresIn: '1h',
  });
  return NextResponse.json({ token });
}

Non-React frameworks (Vue, Angular, vanilla JS)

If you are not using React, you can embed the audit log viewer using an iframe pointed at your own thin wrapper page, or call the REST API directly to build a custom viewer.

iframe embed
<!-- Create a lightweight page that loads the React viewer, then embed it -->
<iframe
  src="https://your-app.com/audit-embed?token=vt_..."
  width="100%"
  height="600"
  style="border: 1px solid #27272a; border-radius: 8px;"
></iframe>

<!-- Or build your own viewer using the REST API: -->
<!-- GET /v1/events with Authorization: Bearer vt_... -->

API Reference

All endpoints require an Authorization: Bearer ak_live_... header.

POST
/v1/events

Create a single audit event. Returns the event with its hash and chain position.

GET
/v1/events

Search and list audit events. Supports query params: q, tenantId, actorId, action, from, to, limit, cursor.

POST
/v1/events/bulk

Create multiple audit events in a single request. Max 1000 events per batch.

POST
/v1/viewer-tokens

Generate a tenant-scoped JWT for the embeddable viewer. Body: { tenantId, expiresIn?, filters? }.

GET
/v1/verify

Verify hash chain integrity. Query params: tenantId (required). Returns chain status and any broken links.

Example: Create event via cURL

terminal
curl -X POST https://api.auditkit.dev/v1/events \
  -H "Authorization: Bearer ak_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "document.updated",
    "actor": { "id": "user_123", "name": "Jane Doe" },
    "target": { "type": "document", "id": "doc_456" },
    "tenantId": "org_acme"
  }'

Authentication

API Keys

API keys are used for server-to-server communication. Create them in the Dashboard Settings. Keys are prefixed for easy identification:

PrefixTypeUsage
ak_live_ProductionProduction environments
ak_test_TestDevelopment and testing

Viewer Tokens

Viewer tokens are short-lived JWTs used by the <AuditLog /> React component. They are scoped to a single tenant and can optionally include pre-set filters. Generate them server-side using createViewerToken() or the REST API.

Event Schema

Every audit event has the following shape. Fields marked with ? are optional.

event schema
{
  id:              string       // UUID v7, auto-generated
  action:          string       // e.g. "document.updated"
  actor: {
    id:            string       // Your user/system ID
    name?:         string       // Display name
    email?:        string       // Email address
  }
  target?: {
    type:          string       // e.g. "document", "user", "permission"
    id:            string       // Your resource ID
    name?:         string       // Display name
  }
  tenantId:        string       // Your tenant/org ID
  severity?:       string       // "info" | "warn" | "error" | "critical" (default: "info")
  metadata?:       object       // Arbitrary key-value pairs
  source_ip?:      string       // Client IP address
  ip_country?:     string       // ISO country code (auto-resolved)
  user_agent?:     string       // Browser/client user agent
  is_anomalous:    boolean      // Set by anomaly detection (read-only)
  occurred_at:     string       // ISO 8601 timestamp (auto-set if omitted)
  row_hash:        string       // SHA-256 hash (auto-generated, read-only)
  prev_hash:       string       // Previous event's hash (read-only)
  chain_position:  number       // Position in tenant's hash chain (read-only)
}

Need help? Open an issue on GitHub or reach out on Discord.