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
let config = Config::builder()
.api_key("sk_live_...")
.webhook_url("https://yourapp.com/webhooks/slipstream")
.webhook_events(vec![
"transaction.confirmed".into(),
"transaction.failed".into(),
"bundle.confirmed".into(),
])
.webhook_notification_level("final") // "all" | "final" | "confirmed"
.build()?;const config = configBuilder()
.apiKey("sk_live_...")
.webhookUrl("https://yourapp.com/webhooks/slipstream")
.webhookEvents(["transaction.confirmed", "transaction.failed"])
.webhookNotificationLevel("final")
.build();Register via SDK
Register — Rust
let webhook = client.register_webhook(
"https://yourapp.com/webhooks/slipstream",
Some(vec![
"transaction.confirmed".into(),
"transaction.failed".into(),
"bundle.confirmed".into(),
]),
Some("final"), // notification level
).await?;
println!("Webhook ID: {}", webhook.id);
println!("Secret: {:?}", webhook.secret); // Only shown on register
println!("Active: {}", webhook.is_active);Register — TypeScript
const webhook = await client.registerWebhook(
"https://yourapp.com/webhooks/slipstream",
["transaction.confirmed", "transaction.failed", "bundle.confirmed"],
"final",
);
console.log("Webhook ID:", webhook.id);
console.log("Secret:", webhook.secret);Register — Python
webhook = await client.register_webhook(
url="https://yourapp.com/webhooks/slipstream",
events=["transaction.confirmed", "transaction.failed", "bundle.confirmed"],
notification_level="final",
)
print(f"Webhook ID: {webhook.id}")
print(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
if let Some(webhook) = client.get_webhook().await? {
println!("URL: {}", webhook.url);
println!("Events: {:?}", webhook.events);
println!("Active: {}", webhook.is_active);
}Delete Webhook — Rust
client.delete_webhook().await?;Get/Delete — TypeScript
const webhook = await client.getWebhook();
if (webhook) console.log("URL:", webhook.url);
await client.deleteWebhook();Get/Delete — Python
webhook = await client.get_webhook()
if webhook:
print(f"URL: {webhook.url}")
await 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
import crypto from "crypto";
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}
app.post("/webhooks/slipstream", (req, res) => {
const signature = req.headers["x-slipstream-signature"] as string;
if (!verifyWebhook(JSON.stringify(req.body), signature, SIGNING_SECRET)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = req.body;
switch (event.type) {
case "transaction.confirmed":
console.log("TX confirmed:", event.data.signature);
break;
case "billing.low_balance":
console.log("Low balance warning");
break;
}
res.status(200).json({ received: true });
});Verify — Python
import hmac
import hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)Verify — Rust
use hmac::{Hmac, Mac};
use sha2::Sha256;
fn verify_webhook(body: &[u8], signature: &str, secret: &str) -> bool {
let mut mac = Hmac::<Sha256>::new_from_slice(secret.as_bytes()).unwrap();
mac.update(body);
let expected = hex::encode(mac.finalize().into_bytes());
expected == signature
}Next Steps
- Billing & Tokens — Billing event webhooks
- Transactions — Transaction lifecycle
- Error Handling — Webhook error scenarios
