Skip to main content
client.triggers covers the whole surface: the type catalog, instance lifecycle, destinations, the event log, and a live stream for local development. Concepts and the wire contract are in Triggers.

Create and enable

The SDKs let you omit the connection; the CLI does not. With neither connection_id nor connection_name, the server uses the application’s default connection and answers MISSING_DEFAULT_CONNECTION when there is none. engini triggers create requires --connection even for types that need no connection at all — see the CLI reference.

Destinations

destination.put() returns one of two shapes. Setting the account default creates a destination the first time — and that response carries the signing secret. Re-pointing an existing default returns the bare destination with no secret. Test for the secret’s presence; do not assume either shape.

Verifying a delivery

verify_webhook / verifyWebhook raises on any rejection — it does not return a boolean. That is deliberate: an ignored False is a webhook endpoint that accepts forgeries, and a raise cannot be ignored by accident. On success it returns the parsed event body.
Three ways to get this wrong, all of which produce a MAC that never matches:
  • Passing the secret without its esec_ prefix. The key is the whole string.
  • Passing a re-serialised body. Frameworks that parse JSON for you must be configured to hand over the raw bytes.
  • Widening the replay window. It defaults to 300 seconds either side of t; the default is the recommendation.

Reading events

events.list is not identical in the two languages. Python takes no top and always auto-paginates to the full set. TypeScript takes top and pages. Code that assumes one shape will not port directly.

Streaming, for local development

subscribe is a second read path over the same events, not a delivery mechanism. Production delivery is a destination plus signature verification. Use the stream while you are building, to watch events arrive without exposing a public URL.
delivery on the stream is always the literal "pending". The stream reports dispatch, before anything has tried to POST. Real delivery state comes only from events.get(id).
Every stream ends — the gateway caps one connection at one hour of wall-clock time, an absolute cap the 20-second heartbeat does not defer, and the cut arrives with no goodbye frame. Both SDKs resume automatically with ?since=<last event id>, so the seam neither duplicates nor skips. Pass auto_resume=False / autoResume: false if you would rather handle it yourself. Two endings stop hard rather than resuming: A gap is surfaced, never papered over with a silent restart from “now” — the whole point of the cursor is that you get to decide what to do about missed events.

Typed errors

Each refines the status-mapped error it sits under, so existing catch blocks keep working.

Runnable examples

The Python SDK ships a worked set under python/examples/triggers/: the catalog and create flow, destinations, a webhook receiver that verifies signatures, subscribing to the stream, and reading events and recovering from a failure. There is no TypeScript equivalent yet; the flows translate directly using the method names above.