Developer Platform

BlogDocsSign In

Blog/Tutorial

Building Real-Time Integrations with Webhooks

Building Real-Time Integrations with Webhooks
MSMarco Silva·March 8, 2026·2 min read

Why webhooks?

Polling an API every few seconds works — until it doesn't. Webhooks flip the model: instead of asking "did anything happen?", the platform tells you the moment something does.

This matters when you're building trading bots, portfolio dashboards, or notification systems where latency is critical.

Setting up your first webhook

Head to the Developer Portal and create a new webhook endpoint. You'll need a publicly accessible URL that can receive POST requests.

server.js
import express from "express";
import crypto from "crypto";
 
const app = express();
app.use(express.json());
 
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-jup-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex");
 
  if (signature !== expected) {
    return res.status(401).json({ error: "Invalid signature" });
  }
 
  console.log("Event received:", req.body.type);
  res.status(200).json({ ok: true });
});
 
app.listen(3000);

Event types

You can subscribe to any combination of events:

EventDescription
swap.completedA swap has been executed successfully
order.filledA limit or trigger order has been filled
order.cancelledAn order was cancelled by the user or system
account.updatedAccount settings or API key changes

Handling failures gracefully

Webhooks can fail — your server might be down, or the request might time out. Jupiter retries failed deliveries with exponential backoff:

  • 1st retry: 30 seconds
  • 2nd retry: 5 minutes
  • 3rd retry: 30 minutes
  • Final retry: 2 hours

After all retries are exhausted, the event is marked as failed and visible in your dashboard.

Idempotency

Each event includes a unique event_id. Always check for duplicates before processing:

import redis
 
r = redis.Redis()
 
def handle_event(event):
    event_id = event["event_id"]
 
    if r.sismember("processed_events", event_id):
        return  # Already handled
 
    # Process the event
    process(event)
 
    r.sadd("processed_events", event_id)
    r.expire(f"processed_events", 86400 * 7)

Best practices

  • Respond quickly — return a 200 status within 5 seconds, then process asynchronously
  • Verify signatures — always validate the x-jup-signature header
  • Log everything — store raw payloads for debugging
  • Use a queue — push events to a message queue for reliable processing

Webhooks are one of the most powerful tools in the platform. Once you've set them up, you'll wonder how you ever built without them.


Marco Silva

March 8, 2026