import { Septor } from '@insureco/septor'
const septor = new Septor({
apiUrl: process.env.SEPTOR_URL,
namespace: process.env.SERVICE_NAME || 'my-service',
})
// Fire-and-forget — NEVER await septor on the critical path
septor.emit('payment.created', {
entityId: orgSlug,
data: { amount, referenceId: paymentId },
metadata: { who: userId },
}).catch((err) => logger.error({ err }, 'Septor emit failed — audit event lost'))
Declare septor as an internalDependency to get SEPTOR_URL auto-injected:
spec:
internalDependencies:
- service: septor
port: 3000 # creates SEPTOR_URL env var
A Septor outage must NEVER break your service. Always fire-and-forget:
// ✅ CORRECT
septor.emit('payment.created', { ... })
.catch((err) => logger.error({ err }, 'Septor emit failed — audit event lost'))
// ❌ WRONG: blocking your user on an audit write
await septor.emit('payment.created', { ... })
| Category | Required Events |
|---|---|
| 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 |
Automatically written by the platform (no code needed):
Use {resource}.{action} dot notation, lowercase:
payment.created ✅
policy.bound ✅
ofac.screen.cleared ✅ (nested resource.sub.action is OK)
payment-created ❌ (hyphens — use dots)
createPayment ❌ (camelCase)
PAYMENT_CREATED ❌ (uppercase)
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.createdAt, event.metadata.who)
}
// Run in background jobs, not request handlers — this is O(n)
const { data } = await septor.verify(orgSlug)
if (!data.valid) {
logger.error({ brokenAt: data.brokenAt }, 'Audit chain broken!')
}
entityId is the primary index — use a stable identifier (orgSlug or userId).catch() is a compliance gap — failures must be logged// ❌ WRONG: blocking on audit write
await septor.emit(...)
// ❌ WRONG: silent failure
septor.emit(...).catch(() => {}) // swallows the error — compliance gap
// ❌ WRONG: vague event type
septor.emit('event.happened', ...)
// ✅ CORRECT
septor.emit('payment.refunded', {
entityId: orgSlug,
data: { amount, reason, refundId },
metadata: { who: userId, why: 'Customer requested refund' },
}).catch((err) => logger.error({ err }, 'Septor emit failed — audit event lost'))
Last updated: February 28, 2026