Getting Started
Core Architecture
Link Engine
Analytics & Attribution
Partners & Affiliates
Third-Party Integrations
Identity & Security
Automation & Messaging
Developer Tools
The following files were used as context for generating this wiki page:
Data Exports enables workspaces and partners to extract large volumes of operational metrics, analytics, and partnership data into structured formats like CSV spreadsheets and ZIP archives. By offering both immediate synchronous responses for small datasets and QStash-driven asynchronous background pipelines for large workloads, the system prevents request timeouts while securely delivering generated artifacts via signed storage URLs and email notifications. Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/api/analytics/export/route.ts
The export system balances request responsiveness with computational safety by routing requests through either a direct synchronous stream or an asynchronous QStash worker pipeline. When client requests query small datasets or request compressed ZIP archives like analytics exports, endpoints execute within standard HTTP timeouts and return binaries directly. When query thresholds exceed predefined volume limits—such as over 1,000 links or commissions—endpoints offload processing to background QStash workers, returning an immediate 202 Accepted status.
Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/api/analytics/export/route.ts:21-128, apps/web/app/api/links/export/route.ts:19-60
The execution path diverges based on data volume checks executed prior to export generation. For links and commissions, endpoints query row counts using getLinksCount and getCommissionsCount, comparing totals against MAX_LINKS_TO_EXPORT (1,000) and MAX_COMMISSIONS_TO_EXPORT (1,000).
Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/api/links/export/route.ts:21-92
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/api/analytics/export/route.ts:21-128, apps/web/app/api/links/export/route.ts:48-60
Note
Analytics exports (/api/analytics/export) bypass the QStash threshold check entirely, utilizing an extended route segment config maxDuration = 300 to stream zipped multi-endpoint analytics payloads directly within the HTTP connection.
Sources: apps/web/app/api/analytics/export/route.ts
Warning
Background export workers authenticate incoming QStash payloads via verifyQstashSignature or withCron, rejecting unverified HTTP posts before parsing payload zulu schemas or querying user records.
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/customers/route.ts
Workspace-authenticated synchronous CSV endpoints handle direct file downloads for links, commissions, payouts, customers, audit logs, and program applications. Each route validates workspace context and permissions using withWorkspace, parses query parameters with dedicated Zod schemas, checks volume limits, and either returns a direct CSV response (200 OK) or offloads execution to QStash background cron jobs (202 Accepted) when dataset sizes exceed defined thresholds.
Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/(ee)/api/payouts/export/route.ts, apps/web/app/api/links/export/route.ts:22-96, apps/web/app/(ee)/api/customers/export/route.ts, apps/web/app/(ee)/api/audit-logs/export/route.ts, apps/web/app/(ee)/api/program-applications/export/route.ts
The synchronous export routes enforce strict access controls, plan restrictions, and volume limits before querying or formatting records.
Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/(ee)/api/payouts/export/route.ts, apps/web/app/api/links/export/route.ts:19-60, apps/web/app/(ee)/api/customers/export/route.ts, apps/web/app/(ee)/api/audit-logs/export/route.ts, apps/web/app/(ee)/api/program-applications/export/route.ts
For workspace link exports, the synchronous request execution follows a precise validation and query sequence:
withWorkspace() -> throwIfClicksUsageExceeded(workspace) -> linksExportQuerySchema.parse(searchParams) -> validateLinksQueryFilters() -> getStartEndDates() -> getLinksCount() -> Threshold check (linksCount > 1000? If yes: qstash.publishJSON() -> 202 Accepted) -> getLinksForWorkspace() -> formatLinksForExport() -> convertToCSV() -> new Response(csvData) with headers.
Sources: apps/web/app/(ee)/api/commissions/export/route.ts, apps/web/app/api/links/export/route.ts:22-96, apps/web/app/(ee)/api/program-applications/export/route.ts
Warning
Link exports automatically tighten query parameters for large workspaces: when workspace total links exceed SORTABLE_LINKS_LIMIT, sortBy forces to "createdAt", and when total links exceed MEGA_WORKSPACE_LINKS_LIMIT, searchMode forces to "exact".
Sources: apps/web/app/api/links/export/route.ts
Note
Audit log exports (/api/audit-logs/export) use an HTTP POST method requiring a JSON body with start and end date strings, explicitly validating plan capabilities via getPlanCapabilities(workspace.plan) before querying records.
Sources: apps/web/app/(ee)/api/audit-logs/export/route.ts
Large-scale background data exports are driven by asynchronous QStash cron worker endpoints located under apps/web/app/(ee)/api/cron/export/. These workers process massive data volumes—such as commissions, payouts, links, customers, and partners—by fetching records in memory-safe asynchronous batches, converting them to CSV format, storing them as downloadable artifacts, and notifying users via email upon completion.
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts
The asynchronous worker endpoints utilize two distinct middleware mechanisms for authentication and payload verification: manual signature validation via verifyQstashSignature or wrapper-based execution via withCron.
For manual signature verification routes (commissions, links, and partners), the incoming request text is read and verified against QStash headers before JSON payload parsing and Zod schema validation. Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts
Routes configured with withCron (payouts and customers) handle signature verification and request lifecycle wrapping implicitly. Sources: apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts
To prevent memory exhaustion during large-scale data retrieval, workers iterate over asynchronous generators that fetch records in controlled batches.
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts
Note
Payouts and customers worker pipelines enforce an explicit upper export bound (MAX_PAYOUTS_EXPORT_LIMIT and MAX_CUSTOMERS_EXPORT_LIMIT set to 100,000 rows), breaking the batch consumption loop once the accumulator reaches capacity.
Sources: apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts
Warning
Link exports automatically adjust searchMode during filter construction when workspace.totalLinks exceeds MEGA_WORKSPACE_LINKS_LIMIT, forcing exact searches instead of fuzzy matching for performance stability.
Sources: apps/web/app/(ee)/api/cron/export/links/route.ts
Analytics exports bundle multi-endpoint analytics datasets into a downloadable ZIP archive. The pipeline queries multiple analytics groupings concurrently or sequentially, transforms response rows into CSV format, packages them via jszip, and returns a buffered node stream with application/zip headers. The primary route handler executes at /api/analytics/export, backed by workspace authentication, rate limiting policies (RATELIMIT_POLICIES.analyticsExport), and plan capability validations. A partner-profile counterpart located at /api/partner-profile/programs/[programId]/analytics/export applies partner-specific enrollment checks, rate limiting (RATELIMIT_POLICIES.partnerAnalyticsExport), and row formatters.
Sources: apps/web/app/api/analytics/export/route.ts:18-132, apps/web/app/(ee)/api/partner-profile/programs/[programId]/analytics/export/route.ts, apps/web/lib/analytics/export-analytics-to-zip.ts:52-93
The export workflow orchestrates parameter normalization, analytics retrieval across grouped endpoints, row formatting, and ZIP file generation.
The execution walkthrough follows this exact call chain:
GET route handler receives request parameters, enforces rate limits, checks click usage, parses queries with parseAnalyticsQuery or partnerProfileAnalyticsQuerySchema, and verifies workspace or program folders.exportAnalyticsToZip() initializes an instance of JSZip and calls getAnalyticsExportEndpoints() to determine which analytics dimensions to query.getAnalytics() fetches data with query filters, composite event configurations, and custom date range overrides.formatRows() transforms them if a formatter is provided (such as formatProgramAnalyticsForExport or formatPartnerAnalyticsForExport).convertToCSV() transforms the record array into a CSV string.zip.file(${endpoint}.csv, ...) appends the CSV to the archive, and zip.generateAsync({ type: "nodebuffer" }) resolves the final buffer returned to the HTTP response.Sources: apps/web/app/api/analytics/export/route.ts:33-121, apps/web/app/(ee)/api/partner-profile/programs/[programId]/analytics/export/route.ts, apps/web/lib/analytics/export-analytics-to-zip.ts:52-93
Note
The maxDuration exported constant on both API route files is explicitly configured to 300 seconds to accommodate large multi-endpoint query aggregation jobs.
Sources: apps/web/app/api/analytics/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/analytics/export/route.ts
The packaging logic filters default analytics endpoints by omitting specified exclusions or skipping single-link top link breakdowns. Partner profile endpoints exclude broader partner metadata dimensions.
The client interacts with the export endpoints via AnalyticsExportButton, which invokes the dynamic route based on whether a partner page context is active, triggers a toast promise, handles blob response creation, and programmatically initiates file downloads. Sources: apps/web/ui/analytics/analytics-export-button.tsx
Click and event log exports handle filtering, pagination, and column projection across Tinybird event logs and raw click streams. The system supports both synchronous responses for smaller datasets and asynchronous background tasks via QStash when event counts exceed designated thresholds.
Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts, apps/web/app/(ee)/api/cron/export/events/workspace/route.ts
The event export route begins by validating plan requirements and querying analytics counts. If the matched events exceed MAX_EVENTS_TO_EXPORT, the job dispatches a background task to QStash and immediately returns an HTTP 202 response. Otherwise, it retrieves the event stream synchronously, maps requested columns using accessors, and outputs a downloadable CSV.
Sources: apps/web/app/(ee)/api/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts
Event export behavior is regulated by strict limits and preset column mappings for different event types.
Sources: apps/web/app/(ee)/api/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts
Warning
Requests exceeding 1000 events bypass synchronous payload rendering entirely. They publish JSON payloads to QStash endpoints (/api/cron/export/events/workspace or /api/cron/export/events/partner) and return HTTP 202 status codes, requiring clients to poll or retrieve results via generated email notifications.
Sources: apps/web/app/(ee)/api/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts
When formatting event log rows, the system evaluates dynamic column accessors and column names via helper mappings, falling back to direct property access and capitalized keys. Partner-specific export workers enforce strict sanitization rules, dropping IP addresses from event payloads and obfuscating customer email fields unless explicit data sharing consent is active. Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/events/export/route.ts, apps/web/app/(ee)/api/cron/export/events/workspace/route.ts
Partner program data exports provide specialized routes for partners to export events and customer records associated with specific programs. These endpoints enforce strict program enrollment verification, check minimum commission thresholds for large programs, and implement privacy safeguards such as customer email obfuscation and pseudorandom name generation when data sharing is disabled.
Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/cron/export/customers/partner/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/export/route.ts
Before processing any partner export, the request pipeline validates partner enrollment and enforces tier-based restrictions. Large programs require a minimum total commission amount in cents before export features are enabled.
Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/cron/export/customers/partner/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/export/route.ts
Warning
If a partner belongs to a program included in LARGE_PROGRAM_IDS, the total commissions converted to cents via toCentsNumber(totalCommissions) must meet or exceed LARGE_PROGRAM_MIN_TOTAL_COMMISSIONS_CENTS. Otherwise, the API throws a forbidden DubApiError.
Sources: apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/customers/export/route.ts
Partner event and customer exports protect end-user privacy when customer data sharing is disabled. IP addresses are systematically stripped from both click and event payloads. Customer email addresses are obfuscated using obfuscateCustomerEmail, and missing names or obfuscated records fall back to pseudorandomly generated names via generateRandomName. Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/partner-profile/programs/[programId]/events/export/route.ts
Tip
When customerDataSharingEnabledAt is present and active, raw customer emails and real customer names are preserved in the export. When absent, email addresses are masked and names default to generated pseudorandom identifiers.
Sources: apps/web/app/(ee)/api/cron/export/events/partner/route.ts, apps/web/app/(ee)/api/cron/export/customers/partner/route.ts
Once large datasets for commissions, payouts, customers, links, partners, and workspace events are gathered and formatted into CSV strings, the background worker pipeline stores the resulting file and notifies the user via email. This process coordinates signature verification, file key generation, signed storage uploads, and React-based email templates.
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/api/cron/export/customers/partner/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts, apps/web/app/(ee)/api/cron/export/events/workspace/route.ts
Background export handlers follow a structured delivery sequence from raw body ingestion to recipient notification.
verifyQstashSignature() -> prisma.user.findUnique() -> createDownloadableExport() -> sendEmail() -> ExportReady()
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts
Storage keys are generated using randomized suffixes combined with entity-specific subdirectories via generateRandomString(16) and generateExportFilename().
Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/payouts/route.ts, apps/web/app/(ee)/api/cron/export/customers/partner/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/app/(ee)/api/cron/export/customers/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts, apps/web/app/(ee)/api/cron/export/events/workspace/route.ts
Warning
If the target user record cannot be found or lacks an associated email address during export processing, the execution terminates early and logs a skip message rather than throwing an unhandled exception. Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts
Once createDownloadableExport returns the downloadUrl, the worker dispatches a notification using @dub/email with the ExportReady React template. The payload passes the recipient email, export type identifier, download URL, and contextual workspace or program metadata. Sources: apps/web/app/(ee)/api/cron/export/commissions/route.ts, apps/web/app/(ee)/api/cron/export/links/route.ts, apps/web/app/(ee)/api/cron/export/partners/route.ts