Skip to content

Quick start

This page shows the whole Knocker shape once:

  1. open a SQLite database
  2. register a webhook endpoint
  3. receive an HTTP webhook into durable rows
  4. run a worker against the same SQLite file
  5. handle the stored event inside Knocker’s transaction

The examples default to Python because it is compact, but every tab is the same product flow over the same SQLite extension.

Knocker stores every receipt as a Delivery. Valid receipts create or correlate to an Event. Workers process events later, either in the same process as your HTTP route or from another process opening the same SQLite file.

Handlers receive a stored event plus a transaction handle. Business writes through that transaction commit atomically with Knocker’s handled transition and queue acknowledgement. If the handler fails, those writes roll back before Knocker records retry/dead-letter state.

For the deeper mental model, read Concepts after this page.

Start with the binding for the runtime you actually use:

import asyncio
import knocker
webhooks = knocker.open("app.db")
automation = webhooks.endpoint(
"automation",
path="/webhooks/automation",
provider="token-header",
secrets=["dev-secret"],
)
@automation.handle("invoice.created")
def handle_invoice(event, tx):
print("handled", event.id)
result = automation.receive(
body=b'{"id":"evt_1","type":"invoice.created"}',
headers={"X-Knocker-Token": "dev-secret"},
)
stop = asyncio.Event()
worker = asyncio.create_task(webhooks.run_worker(stop_event=stop))
await asyncio.sleep(0.1)
stop.set()
await worker