Webhooks
Receive real-time notifications for transaction status changes, bundle results, and billing events. Webhooks can be configured via the SDK or at connect time through the config builder.
Configure at Connect Time
1let config = Config::builder()
2 .api_key("sk_live_...")
3 .webhook_url("https://yourapp.com/webhooks/slipstream")
4 .webhook_events(vec![
5 "transaction.confirmed".into(),
6 "transaction.failed".into(),
7 "bundle.confirmed".into(),
8 ])
9 .webhook_notification_level("final") // "all" | "final" | "confirmed"
10 .build()?;1const config = configBuilder()
2 .apiKey("sk_live_...")
3 .webhookUrl("https://yourapp.com/webhooks/slipstream")
4 .webhookEvents(["transaction.confirmed", "transaction.failed"])
5 .webhookNotificationLevel("final")
6 .build();Register via SDK
Register — Rust
1let webhook = client.register_webhook(
2 "https://yourapp.com/webhooks/slipstream",
3 Some(vec![
4 "transaction.confirmed".into(),
5 "transaction.failed".into(),
6 "bundle.confirmed".into(),
7 ]),
8 Some("final"), // notification level
9).await?;
10
11println!("Webhook ID: {}", webhook.id);
12println!("Secret: {:?}", webhook.secret); // Only shown on register
13println!("Active: {}", webhook.is_active);Register — TypeScript
1const webhook = await client.registerWebhook(
2 "https://yourapp.com/webhooks/slipstream",
3 ["transaction.confirmed", "transaction.failed", "bundle.confirmed"],
4 "final",
5);
6
7console.log("Webhook ID:", webhook.id);
8console.log("Secret:", webhook.secret);Register — Python
1webhook = await client.register_webhook(
2 url="https://yourapp.com/webhooks/slipstream",
3 events=["transaction.confirmed", "transaction.failed", "bundle.confirmed"],
4 notification_level="final",
5)
6
7print(f"Webhook ID: {webhook.id}")
8print(f"Secret: {webhook.secret}")Event Types
| Event | Description |
|---|---|
transaction.sent | Transaction sent to the network |
transaction.confirmed | Transaction confirmed on-chain |
transaction.failed | Transaction failed or expired |
bundle.sent | Bundle sent to the network |
bundle.confirmed | Bundle confirmed on-chain |
bundle.failed | Bundle failed or dropped |
billing.low_balance | Token balance below threshold |
billing.depleted | Token balance reached zero |
billing.deposit_received | SOL deposit received and credited |
Notification Levels
| Level | Events Delivered |
|---|---|
all | Every status change (sent, confirmed, failed) |
final | Only final states (confirmed + failed) — default |
confirmed | Only confirmed events |
Managing Webhooks
Get Current Webhook — Rust
1if let Some(webhook) = client.get_webhook().await? {
2 println!("URL: {}", webhook.url);
3 println!("Events: {:?}", webhook.events);
4 println!("Active: {}", webhook.is_active);
5}Delete Webhook — Rust
1client.delete_webhook().await?;Get/Delete — TypeScript
1const webhook = await client.getWebhook();
2if (webhook) console.log("URL:", webhook.url);
3
4await client.deleteWebhook();Get/Delete — Python
1webhook = await client.get_webhook()
2if webhook:
3 print(f"URL: {webhook.url}")
4
5await client.delete_webhook()HMAC-SHA256 Verification
Every webhook request includes an X-Slipstream-Signature header. Verify it with the secret returned during registration.
Verify — Node.js
1import crypto from "crypto";
2
3function verifyWebhook(body: string, signature: string, secret: string): boolean {
4 const expected = crypto
5 .createHmac("sha256", secret)
6 .update(body)
7 .digest("hex");
8 return crypto.timingSafeEqual(
9 Buffer.from(signature),
10 Buffer.from(expected),
11 );
12}
13
14app.post("/webhooks/slipstream", (req, res) => {
15 const signature = req.headers["x-slipstream-signature"] as string;
16 if (!verifyWebhook(JSON.stringify(req.body), signature, SIGNING_SECRET)) {
17 return res.status(401).json({ error: "Invalid signature" });
18 }
19
20 const event = req.body;
21 switch (event.type) {
22 case "transaction.confirmed":
23 console.log("TX confirmed:", event.data.signature);
24 break;
25 case "billing.low_balance":
26 console.log("Low balance warning");
27 break;
28 }
29
30 res.status(200).json({ received: true });
31});Verify — Python
1import hmac
2import hashlib
3
4def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
5 expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
6 return hmac.compare_digest(signature, expected)Verify — Rust
1use hmac::{Hmac, Mac};
2use sha2::Sha256;
3
4fn verify_webhook(body: &[u8], signature: &str, secret: &str) -> bool {
5 let mut mac = Hmac::<Sha256>::new_from_slice(secret.as_bytes()).unwrap();
6 mac.update(body);
7 let expected = hex::encode(mac.finalize().into_bytes());
8 expected == signature
9}Next Steps
- Billing & Tokens — Billing event webhooks
- Transactions — Transaction lifecycle
- Error Handling — Webhook error scenarios