Skip to content

Webhooks

Subscribe to signed HTTP callbacks for the lifecycle of every transaction you submit through /v1/swap (and, going forward, /v1/send).

All webhook endpoints require a self-service API key (vk_...). Manage keys at app.venum.dev.

Event types

EventMeaning
landedEarliest signal — the network has seen your tx in a shred. Pre-processing: not yet executed. ~100ms after broadcast.
processedThe cluster has executed your tx. Default for new webhooks. Sub-second under typical conditions.
confirmedSupermajority commitment. Reached ~one block after processed.
finalizedRooted and irreversible. Reached ~12-13s after processed.
failedYour tx errored on chain. Terminal — mutually exclusive with the commitment events for the same signature.

Subscribe to any subset on create. The event taxonomy matches the /v1/stream/tx SSE stream, so a webhook + SSE consumer of the same signature see consistent state.

POST /v1/webhooks

Create a webhook subscription. The webhook secret is returned exactly once in this response — capture it now or rotate by deleting and re-creating.

Request

http
POST /v1/webhooks
Content-Type: application/json
X-API-Key: vk_...

Body

FieldTypeRequiredDescription
urlstringYesPublic HTTPS URL where events will be POSTed. Localhost / private network hostnames are rejected — for local dev, expose your handler via an ngrok or cloudflared tunnel. Max 512 chars.
eventsstring[]NoSubset of event types to subscribe to. Defaults to ["processed"].

Example

json
{
  "url": "https://my-app.example.com/webhooks/venum",
  "events": ["processed", "finalized"]
}

Response 201

json
{
  "id": 42,
  "url": "https://my-app.example.com/webhooks/venum",
  "events": ["processed", "finalized"],
  "createdAt": "2026-05-17T20:00:00.000Z",
  "pausedAt": null,
  "secret": "whsec_3f9d1c8a2b7e0f5d6a4c8b2e9f1d3a7c5b8e0f2d4a6c8b1e"
}

WARNING

The secret is shown once. Store it now — there is no endpoint to retrieve it later.

Errors

StatusDescription
400Missing/malformed url, unknown event type, or no dbApiKeyId (env-keyed callers cannot subscribe).
401Missing or invalid API key.
409Webhook limit reached (20 per key).

GET /v1/webhooks

List every webhook on the calling key. Secrets are not returned.

Response 200

json
{
  "webhooks": [
    {
      "id": 42,
      "url": "https://my-app.example.com/webhooks/venum",
      "events": ["processed", "finalized"],
      "createdAt": "2026-05-17T20:00:00.000Z",
      "pausedAt": null
    }
  ]
}

PATCH /v1/webhooks/:id

Pause or resume a webhook. Paused webhooks remain in the list but do not receive events until resumed.

json
{ "paused": true }

Response 200: returns the updated webhook (same shape as GET).

DELETE /v1/webhooks/:id

Permanently delete a webhook. The associated secret becomes unusable.

json
{ "deleted": true }

404 if the webhook isn't found or isn't owned by the calling key.

Event payload

Each delivery POSTs a JSON body matching the subscribed event type:

http
POST /your/webhook/path
Content-Type: application/json
X-Venum-Signature: t=1715900000000,v1=4b7f...
json
{
  "type": "processed",
  "signature": "5KxabcDef...3nF",
  "slot": 254812345,
  "inputMint": "So11111111111111111111111111111111111111112",
  "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "inputAmount": "1000000000",
  "outputAmount": "143820000",
  "dex": "orca",
  "poolAddress": "Hp53XEt...UnxVtA",
  "walletAddress": "9zT...kqW",
  "quoteId": "q_abcd1234..."
}

Common fields

FieldTypeDescription
typestringThe event type — "landed" / "processed" / "confirmed" / "finalized" / "failed".
signaturestringBase58 transaction signature. Use this as the idempotency key on your side.
slotnumberSlot number where the event was observed.
inputMint / outputMintstringToken mint addresses.
inputAmount / outputAmountstringRaw token amounts (lamports / token base units), as strings to preserve precision.
dexstring | nullVenue routed through (e.g. "orca", "raydium-clmm", "meteora-dlmm").
poolAddressstring | nullPool routed through. For multi-hop routes, comma-joined.
walletAddressstringThe user's wallet (signer of the swap).
quoteIdstringThe quoteId returned by /v1/swap/build.

failed event

When type === "failed", the payload includes an err field with the on-chain error and no outputAmount (the tx didn't execute):

json
{
  "type": "failed",
  "signature": "5K...",
  "slot": 254812345,
  "err": "InstructionError: [3, { Custom: 6004 }]",
  ...
}

Signature header

Every webhook delivery includes an X-Venum-Signature header:

X-Venum-Signature: t=<unix_ms>,v1=<hex>
ComponentDescription
tUnix milliseconds when the payload was signed.
v1Lowercase hex of HMAC_SHA256(secret, "<t>.<rawBody>").

Reject deliveries where t is older than your tolerance window (5 minutes recommended) before comparing v1. See the Webhooks guide for verification examples in Node and Python.

Delivery semantics

  • At-least-once. Use the transaction signature as your idempotency key. The same (signature, type) pair will not be delivered more than once to any given webhook within the same process lifetime.
  • Retries. Failed deliveries retry up to 3 times with exponential backoff (~0.5s, ~1s, ~2s). Non-2xx responses count as failure.
  • Timeout. Each delivery attempt times out after 5 seconds.

Rate limits

Webhook management endpoints share the dashboard rate-limit bucket:

TierLimit
free30 / min
starter120 / min
pro300 / min