← Back to Skills

Septor Audit Trail

Write immutable audit events for payments, policies, and compliance operations.

Ruleplatform

About

How to wire your service into Septor — the platform's immutable audit trail. Covers SDK setup, the mandatory fire-and-forget emit pattern, which event types are required (payments, policies, compliance, authorization), event naming conventions, reading audit trails, and cryptographic chain verification.

Skill Content

This is the raw markdown that gets installed as a Claude Code rule.

# Septor — Immutable Audit Trail

## What this skill covers
Writing audit events, reading the audit trail, what operations MUST be Septor-wired, and chain integrity verification.

## SDK Setup

```typescript
import { Septor } from '@insureco/septor'

const septor = new Septor({
  apiUrl: process.env.SEPTOR_URL,
  namespace: process.env.SERVICE_NAME || 'my-service',
})
```

Declare septor as an `internalDependency` to auto-inject `SEPTOR_URL`. Port defaults to 3000 and can be omitted:

```yaml
spec:
  internalDependencies:
    - service: septor   # creates SEPTOR_URL env var
```

## Writing Events

```typescript
// CORRECT: fire-and-forget with error logging — NEVER await on the request path
septor.emit('payment.created', {
  entityId: orgSlug,          // who/what this event concerns (index key)
  data: {
    amount: 5000,
    currency: 'USD',
    referenceId: paymentId,
  },
  metadata: {
    who: userId,              // the actor (user ID or service name)
    why: 'User initiated premium payment',
  },
}).catch((err) => logger.error({ err }, 'Septor emit failed — audit event lost'))

// WRONG: blocking your response on an audit write
await septor.emit(...)  // never do this
```

A Septor outage must never break your service. Always fire-and-forget with `.catch()`.

## What MUST Be Septor-Wired

Every financial, compliance, and authorization event is mandatory:

| Category | Required Event Types |
|----------|---------------------|
| Payments | `payment.created`, `payment.completed`, `payment.failed`, `payment.refunded` |
| Policies | `policy.bound`, `policy.endorsed`, `policy.cancelled`, `policy.renewed` |
| Compliance | `ofac.cleared`, `ofac.flagged`, `kyc.verified`, `kyc.failed` |
| Authorization | `user.login`, `permission.granted`, `permission.revoked` |
| Data Access | `record.accessed`, `report.exported`, `data.modified` |

Not required (platform handles automatically):
- Deploy events (iec-builder writes these)
- Gas events (Janus writes these)
- Credential rotations (builder writes these)

## Event Naming Convention

Use dot-separated `{resource}.{action}` format, lowercase:

```
payment.created       ✓
policy.bound          ✓
ofac.screen.cleared   ✓  (nested resource.sub.action is OK)

payment-created       ✗  (use dots, not hyphens)
createPayment         ✗  (use resource.action, not camelCase)
PAYMENT_CREATED       ✗  (lowercase only)
```

## Reading Audit Trails

```typescript
const { data } = await septor.query({
  entityId: orgSlug,
  eventType: 'payment.created',  // optional filter
  from: '2024-01-01',
  to: '2024-01-31',
  limit: '100',
})

for (const event of data.events) {
  console.log(event.eventType, event.metadata.who, event.data, event.chainIndex)
}
```

## Verifying Chain Integrity

```typescript
// Each event is cryptographically linked to the previous one
// Run this in background jobs, not request handlers — it's O(n)
const { data } = await septor.verify(orgSlug)

if (!data.valid) {
  logger.error({ entityId: orgSlug, brokenAt: data.brokenAt }, 'Audit chain broken!')
}
```

## Key Facts
- Each event gets a cryptographic hash linked to the previous event — the chain is tamper-evident
- `entityId` is the primary index — use a stable identifier like `orgSlug` or `userId`
- Events are immutable — once written, they cannot be modified or deleted
- Namespace scoping means each service sees only its own events

## Common Mistakes
- Awaiting `septor.emit()` on the request path — always fire-and-forget with `.catch()`
- Not logging the `.catch()` error — silent failures mean compliance gaps with no alert
- Using vague event types like `event.happened` — be specific: `payment.refunded`
- Forgetting `internalDependencies` for septor — `SEPTOR_URL` won't be injected
- Using inconsistent `entityId` for the same entity — pick one stable ID and stick to it
- Omitting `metadata.who` — compliance audits require knowing the actor

Install

Copy the skill content and save it to:

~/.claude/rules/septor-audit.md
Download .md

Coming soon via CLI:

tawa chaac install septor-audit

Details

Format
Rule
Category
platform
Version
1.0.0
Tokens
~900
Updated
2026-03-01
septorauditcompliancepaymentsimmutableevents