How the Dub Referral Sale Sweep Complements Billing Webhooks for Renewals and Top‑Ups

Open SEO employs a dual‑layer attribution strategy where billing webhooks capture initial referral sales in real time while a nightly Dub referral sale sweep catches subscription renewals and top‑up purchases that webhooks miss.

Reliable referral tracking demands capturing both the first payment and all subsequent revenue events attributed to a Dub referral. The Open SEO codebase implements a resilient pipeline that combines immediate webhook processing with a periodic batch job, ensuring complete revenue attribution across the entire customer lifecycle.

The Billing Webhook Path for Immediate Attribution

When a referred organization generates a paid invoice, the system must record that sale in Dub without delay. The Autumn billing webhook provides this real‑time capability by triggering attribution logic instantly upon invoice creation.

Implementation in autumn-webhook.ts

The autumnWebhookHandler located in src/server/billing/autumn-webhook.ts imports trackDubSalesForOrganization and invokes it immediately after processing a successful invoice. This ensures prompt attribution for first‑time paid subscriptions, capturing the initial conversion as it happens.

import { trackDubSalesForOrganization } from "@/server/referrals/dub";

export async function autumnWebhookHandler(customerId: string) {
  // Process the Autumn billing webhook payload...
  await trackDubSalesForOrganization(customerId); // Instant attribution
}

The Daily Dub Referral Sale Sweep

Autumn’s billing.updated event does not fire for subscription renewals or one‑time top‑up purchases. Relying solely on webhooks creates a data gap where recurring revenue and add‑on purchases go unattributed to the original referral.

Why Webhooks Miss Renewals and Top‑Ups

According to the implementation comments in src/server/referrals/dub.ts, Autumn’s webhook system lacks documentation confirming delivery for renewal events or one‑time top‑ups. Without a secondary catch‑mechanism, these critical revenue events—essential for accurate lifetime value calculations—would be permanently lost.

How the Sweep Captures Missed Revenue

The sweepDubReferredOrganizations function runs as a nightly cron job. It iterates over every organization carrying a Dub referral pin, examining invoices created within the last 45 days. For each qualifying invoice, the function constructs a Dub sale request and calls trackDubSale, ensuring that renewals, top‑ups, and invoices that were still pending when the original webhook fired are properly recorded.

import { sweepDubReferredOrganizations } from "@/server/referrals/dub";

export async function dailyCron() {
  // Executes once per day
  await sweepDubReferredOrganizations(); // Catches renewals and top-ups
}

Key Implementation Files

Referral attribution logic spans several dedicated modules:

How Both Systems Work Together

The immediate webhook captures the first paid event when it occurs, providing real‑time attribution for new subscriptions. The daily sweep guarantees that any subsequent revenue events—renewals, top‑ups, or late‑closing invoices—that the webhook cannot see are still attributed to the original Dub referral. This architecture operates idempotently, ensuring that running both systems concurrently creates comprehensive coverage without duplicate records.

Summary

  • Billing webhooks in src/server/billing/autumn-webhook.ts provide instant attribution by calling trackDubSalesForOrganization immediately after invoice creation.
  • Daily sweep in src/server/referrals/dub.ts executes sweepDubReferredOrganizations to catch renewals and top‑ups that Autumn webhooks miss, scanning invoices from the last 45 days.
  • The combined approach ensures reliable, duplicate‑free tracking of all referral revenue regardless of whether it originates from new subscriptions, renewals, or one‑time purchases.

Frequently Asked Questions

Why doesn't the billing webhook catch subscription renewals?

Autumn’s billing.updated event is not documented to fire for subscription renewals or one‑time top‑up purchases according to comments in src/server/referrals/dub.ts. Without the daily Dub referral sale sweep, these revenue events would remain unattributed to the originating referral.

How does Open SEO prevent duplicate sale tracking?

Both the webhook handler and the daily sweep utilize the same trackDubSale function, which operates idempotently. Processing the same invoice twice—once via webhook and once via sweep—does not create duplicate records in Dub, ensuring data integrity while maximizing attribution coverage.

What is the 45‑day lookback window for?

The sweepDubReferredOrganizations function examines invoices created within the last 45 days to balance comprehensiveness against performance. This window captures invoices that were still open when the webhook originally fired, as well as recent renewals and top‑ups, without reprocessing excessive historical data.

Where is the Dub sale payload constructed?

The payload sent to Dub’s /track/sale endpoint is built in src/server/referrals/dub-sale.ts. This module is shared between the billing webhook path and the daily sweep, ensuring consistent data formatting and API interaction regardless of which system initiates the tracking call.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →