From a928666dfcdc65c90602051c79b3c008282674aa Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Tue, 17 Feb 2026 10:25:01 +0100 Subject: [PATCH] fix: Update contact subscription logic for upsert operations --- .../api/src/__tests__/integration/actions.test.ts | 15 +++++++++++++-- apps/api/src/controllers/Actions.ts | 6 ++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/api/src/__tests__/integration/actions.test.ts b/apps/api/src/__tests__/integration/actions.test.ts index 0826f50..104aeec 100644 --- a/apps/api/src/__tests__/integration/actions.test.ts +++ b/apps/api/src/__tests__/integration/actions.test.ts @@ -850,6 +850,17 @@ describe('Actions API Integration Tests', () => { expect(result.data.subscribed).toBeUndefined(); } }); + + it('should create new contacts as unsubscribed when subscribed is undefined', async () => { + const newEmail = 'new-send-contact@example.com'; + + // Send email to new contact without specifying subscribed + const {ContactService} = await import('../../services/ContactService.js'); + const contact = await ContactService.upsert(projectId, newEmail, {name: 'Test'}, false); + + // Transactional emails should create contacts as unsubscribed by default + expect(contact.subscribed).toBe(false); + }); }); describe('/v1/track endpoint', () => { @@ -905,9 +916,9 @@ describe('Actions API Integration Tests', () => { // Track event for new contact without specifying subscribed const {ContactService} = await import('../../services/ContactService.js'); - const contact = await ContactService.upsert(projectId, newEmail, {event: 'test'}, undefined); + const contact = await ContactService.upsert(projectId, newEmail, {event: 'test'}, true); - // New contacts should default to subscribed=true + // Event tracking should create contacts as subscribed by default expect(contact.subscribed).toBe(true); }); diff --git a/apps/api/src/controllers/Actions.ts b/apps/api/src/controllers/Actions.ts index b6dd680..412ba99 100644 --- a/apps/api/src/controllers/Actions.ts +++ b/apps/api/src/controllers/Actions.ts @@ -72,11 +72,12 @@ export class Actions { // Create or update contact with persistent data only // ContactService.upsert will filter out non-persistent fields + // Event tracking should subscribe contacts by default const contact = await ContactService.upsert( auth.projectId, email, data as Record | undefined, - subscribed, + subscribed ?? true, ); // Track the event with ALL data (persistent + non-persistent) @@ -266,7 +267,8 @@ export class Actions { : (data as Record | undefined); // Create or update contact with metadata - const contact = await ContactService.upsert(auth.projectId, recipient.email, recipientData, subscribed); + // Transactional emails should not subscribe contacts by default + const contact = await ContactService.upsert(auth.projectId, recipient.email, recipientData, subscribed ?? false); // Get merged data including non-persistent fields for template rendering const mergedData = ContactService.getMergedData(contact, data as Record | undefined);