Documentation index

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

Rust
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()?;
TypeScript
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

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

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

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

EventDescription
transaction.sentTransaction sent to the network
transaction.confirmedTransaction confirmed on-chain
transaction.failedTransaction failed or expired
bundle.sentBundle sent to the network
bundle.confirmedBundle confirmed on-chain
bundle.failedBundle failed or dropped
billing.low_balanceToken balance below threshold
billing.depletedToken balance reached zero
billing.deposit_receivedSOL deposit received and credited

Notification Levels

LevelEvents Delivered
allEvery status change (sent, confirmed, failed)
finalOnly final states (confirmed + failed) — default
confirmedOnly confirmed events

Managing Webhooks

Get Current Webhook — Rust

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

Rust
client.delete_webhook().await?;

Get/Delete — TypeScript

TypeScript
const webhook = await client.getWebhook();
if (webhook) console.log("URL:", webhook.url);

await client.deleteWebhook();

Get/Delete — Python

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

TypeScript
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

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

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