From 3456af12fe6900c43e4d98e5f7c73f47a8237ffa Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Thu, 21 May 2026 00:08:50 -0400 Subject: [PATCH] bump to reddit v3 api (#209) --- src/routes/__root.tsx | 2 +- src/routes/_app/billing.tsx | 2 +- src/routes/_authenticated.subscribe.tsx | 2 +- src/server/lib/reddit-conversions.ts | 54 ++++++++++++------------ src/serverFunctions/redditConversions.ts | 8 ++-- 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 224fea5..074adef 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -131,7 +131,7 @@ function PostHogBootstrap() { redditSignupInFlightRef.current = true; void captureRedditConversionEvent({ - data: { attribution, eventType: "SignUp" }, + data: { attribution, eventType: "SIGN_UP" }, }) .then((result) => { if (result.status === "sent" || result.status === "already_sent") { diff --git a/src/routes/_app/billing.tsx b/src/routes/_app/billing.tsx index af4891c..dfb87c2 100644 --- a/src/routes/_app/billing.tsx +++ b/src/routes/_app/billing.tsx @@ -81,7 +81,7 @@ function BillingPageContent() { if (!attribution) return; void captureRedditConversionEvent({ - data: { attribution, eventType: "Purchase" }, + data: { attribution, eventType: "PURCHASE" }, }); }, [billingRouteState, checkoutCompleted]); diff --git a/src/routes/_authenticated.subscribe.tsx b/src/routes/_authenticated.subscribe.tsx index 599eda3..c063de3 100644 --- a/src/routes/_authenticated.subscribe.tsx +++ b/src/routes/_authenticated.subscribe.tsx @@ -59,7 +59,7 @@ function SubscribePageContent() { const attribution = getStoredRedditAttribution(); if (attribution) { void captureRedditConversionEvent({ - data: { attribution, eventType: "Purchase" }, + data: { attribution, eventType: "PURCHASE" }, }).finally(() => { void navigate({ to: "/", replace: true }); }); diff --git a/src/server/lib/reddit-conversions.ts b/src/server/lib/reddit-conversions.ts index 354f076..7a74fe0 100644 --- a/src/server/lib/reddit-conversions.ts +++ b/src/server/lib/reddit-conversions.ts @@ -7,7 +7,7 @@ import { type RedditAttributionInput, } from "@/shared/reddit-attribution"; -type RedditConversionType = "SignUp" | "Purchase"; +type RedditConversionType = "SIGN_UP" | "PURCHASE"; type CaptureRedditConversionArgs = { attribution: RedditAttributionInput; @@ -34,12 +34,12 @@ async function sha256(value: string) { } function getRedditConfig() { - const accountId = getEnv("REDDIT_AD_ACCOUNT_ID") || getEnv("REDDIT_PIXEL_ID"); + const pixelId = getEnv("REDDIT_PIXEL_ID"); const accessToken = getEnv("REDDIT_CONVERSIONS_ACCESS_TOKEN"); - if (!accountId || !accessToken) return null; + if (!pixelId || !accessToken) return null; - return { accountId, accessToken }; + return { accessToken, pixelId }; } async function upsertAttribution(args: CaptureRedditConversionArgs) { @@ -88,7 +88,7 @@ async function hasSentConversion(args: CaptureRedditConversionArgs) { const existing = await db.query.redditAttributions.findFirst({ where: eq(redditAttributions.userId, args.userId), }); - return args.eventType === "SignUp" + return args.eventType === "SIGN_UP" ? Boolean(existing?.signupSentAt) : Boolean(existing?.purchaseSentAt); } @@ -96,7 +96,7 @@ async function hasSentConversion(args: CaptureRedditConversionArgs) { async function markConversionSent(args: CaptureRedditConversionArgs) { const now = new Date().toISOString(); const sentColumn = - args.eventType === "SignUp" ? "signupSentAt" : "purchaseSentAt"; + args.eventType === "SIGN_UP" ? "signupSentAt" : "purchaseSentAt"; await db .update(redditAttributions) @@ -118,36 +118,38 @@ export async function captureRedditConversion( const config = getRedditConfig(); if (!config) return "stored" as const; - const eventMetadata: Record = { + const metadata: Record = { conversion_id: args.conversionId, - transaction_id: args.conversionId, }; if (args.valueDecimal !== undefined) { - eventMetadata.value_decimal = args.valueDecimal; - eventMetadata.currency = args.currency ?? "USD"; - eventMetadata.item_count = 1; + metadata.currency = args.currency ?? "USD"; + metadata.item_count = 1; + metadata.value = args.valueDecimal; } const payload = { - events: [ - { - click_id: args.attribution.clickId, - event_at: new Date().toISOString(), - event_type: { - tracking_type: args.eventType, + data: { + events: [ + { + action_source: "WEBSITE", + click_id: args.attribution.clickId, + event_at: Date.now(), + metadata, + type: { + tracking_type: args.eventType, + }, + user: { + email: await sha256(args.email), + external_id: await sha256(args.userId), + uuid: args.attribution.uuid, + }, }, - event_metadata: eventMetadata, - user: { - email: await sha256(args.email), - external_id: await sha256(args.userId), - uuid: args.attribution.uuid, - }, - }, - ], + ], + }, }; const response = await fetch( - `https://ads-api.reddit.com/api/v2.0/conversions/events/${config.accountId}`, + `https://ads-api.reddit.com/api/v3/pixels/${config.pixelId}/conversion_events`, { method: "POST", headers: { diff --git a/src/serverFunctions/redditConversions.ts b/src/serverFunctions/redditConversions.ts index 598e55b..c4b1b56 100644 --- a/src/serverFunctions/redditConversions.ts +++ b/src/serverFunctions/redditConversions.ts @@ -6,7 +6,7 @@ import { requireAuthenticatedContext } from "@/serverFunctions/middleware"; const conversionInputSchema = z.object({ attribution: redditAttributionSchema, - eventType: z.enum(["SignUp", "Purchase"]), + eventType: z.enum(["SIGN_UP", "PURCHASE"]), }); export const captureRedditConversionEvent = createServerFn({ method: "POST" }) @@ -15,13 +15,13 @@ export const captureRedditConversionEvent = createServerFn({ method: "POST" }) .handler(async ({ data, context }) => { const status = await captureRedditConversion({ attribution: data.attribution, - conversionId: `${data.eventType.toLowerCase()}:${context.userId}`, + conversionId: `${data.eventType === "SIGN_UP" ? "signup" : "purchase"}:${context.userId}`, email: context.userEmail, eventType: data.eventType, organizationId: context.organizationId, userId: context.userId, - valueDecimal: data.eventType === "Purchase" ? 10 : undefined, - currency: data.eventType === "Purchase" ? "USD" : undefined, + valueDecimal: data.eventType === "PURCHASE" ? 10 : undefined, + currency: data.eventType === "PURCHASE" ? "USD" : undefined, }); return { status };