0Bit Documentation

Build an idempotent event log

Record webhook events once, route workers safely, and make duplicate delivery harmless.

Webhook delivery is at least once. Your event log is what turns duplicate delivery, replay, retries, and worker crashes into safe operational behavior.

Dedupe before side effects

Insert the event id into a unique log before fulfillment. If the insert says the event already exists, acknowledge the webhook and do not run side effects again.

Event log shape

FieldPurpose
event_idUnique event identifier and dedupe key.
event_typeRoutes the event to the correct worker.
received_atSupports debugging and latency monitoring.
processed_atShows when business logic completed.
processing_statePending, processing, succeeded, ignored, or failed.
related_referenceSession id, rail id, quote id, customer id, or your local attempt id.

Insert-once flow

Implementation pattern

async function recordVerifiedEvent(event: ObitWebhookEvent) {
  const inserted = await db.webhookEvents.insertIgnore({
    eventId: event.id,
    eventType: event.type,
    relatedReference: event.data.id,
    processingState: 'pending',
    receivedAt: new Date(),
  });

  if (!inserted) {
    return { duplicate: true };
  }

  await jobs.enqueue('process_obit_event', { eventId: event.id });
  return { duplicate: false };
}

async function processRecordedEvent(eventId: string) {
  const event = await db.webhookEvents.claimForProcessing(eventId);
  if (!event) return;

  try {
    await applyBusinessTransition(event);
    await db.webhookEvents.markSucceeded(eventId);
  } catch (error) {
    await db.webhookEvents.markFailed(eventId, redactError(error));
    throw error;
  }
}

State transitions

Current stateNext stateTrigger
PendingProcessingWorker claims the event.
ProcessingSucceededBusiness transition finishes.
ProcessingFailedWorker error after safe logging.
FailedProcessingOperator or scheduled retry.
Any terminalSame terminalDuplicate event or replay.

Guardrails

  • Put a unique constraint on event id.
  • Keep raw payload access restricted and redact it from logs.
  • Store enough identifiers for support without storing secrets.
  • Make business transitions idempotent too, not just event insertion.
  • Route unknown event types to an ignored or review state, not a crash loop.

On this page