Expand description
Webhook delivery for Rust backed by Postgres or SQLite.
HMAC-SHA256 signing, exponential backoff retry, dead letter queue, idempotent sends, event-type filtering, circuit breaker, and SSRF protection — all backed by your existing database. No Redis, no external queue service.
§Quick start
use webhooksmith::WebhookEngine;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = WebhookEngine::builder()
.database_url("postgres://user:pass@localhost/mydb")
.build()
.await?;
engine.migrate().await?;
let endpoint = engine
.register("https://partner.example.com/webhooks", "your-signing-secret")
.await?;
engine.send("order.created", json!({"id": 1001}), endpoint.id).await?;
// Blocks until the process exits; use run_graceful() for signal handling
engine.run().await;
}§Transactional outbox
Write your business data and the webhook event in the same database transaction. If the transaction rolls back, the event never exists.
ⓘ
let mut tx = engine.pool().begin().await?;
// Your business logic — use any sqlx query here
sqlx::query!("INSERT INTO orders (id) VALUES ($1)", order_id)
.execute(&mut *tx).await?;
// Only queued if this transaction commits
engine.send_in_tx("order.created", json!({"id": order_id}), endpoint_id, &mut tx).await?;
tx.commit().await?;§Features
| Feature | Description |
|---|---|
postgres (default) | Full transactional outbox using SELECT FOR UPDATE SKIP LOCKED |
sqlite | SqliteEngine — same API, no Postgres required |
§See also
WebhookEngine— core engine (Postgres)SqliteEngine— SQLite engine (requiresfeatures = ["sqlite"])worker::DeliveryWorker— background delivery loop- Full documentation
Re-exports§
pub use model::is_private_host;pub use model::is_private_ip;pub use engine::WebhookEngine;pub use error::HooksmithError;pub use error::Result;pub use model::DeliveryAttempt;pub use model::Endpoint;pub use model::EventStatus;pub use model::NewEndpoint;pub use model::QueueStats;pub use model::UpdateEndpoint;pub use model::WebhookEvent;pub use model::event_matches_filter;pub use worker::DeliveryWorker;pub use worker::SsrfSafeDnsResolver;pub use sqlite_engine::SqliteEngine;