Skip to content

🐞 - Campaign unsubscribe does not emit a contact.updated webhook #413

Description

@kulkam

What happened?

Task description written with the help of Claude Code :)

When a contact unsubscribes through a campaign (body link or RFC 8058 one-click), no webhook is emitted. Webhook consumers cannot detect campaign unsubscribes and have no per-contact signal to sync suppression state — only the aggregate campaign.unsubscribed counter changes.

Where

  • contact.updated is emitted only from contact-service.ts:
    • addOrUpdateContactapps/web/src/server/service/contact-service.ts:159
    • updateContactInContactBook:225
    • deleteContactInContactBook (contact.deleted) → :250
  • The campaign unsubscribe path bypasses these — unsubscribeContact() does a raw db.contact.update({ subscribed: false }) with no emitContactEvent:
    apps/web/src/server/service/campaign-service.ts:580-622 (update at :600).
  • Both the body GET page and the one-click POST route funnel into unsubscribeContact, so neither emits a webhook.

Suggested fix

Emit contact.updated from unsubscribeContact (and the re-subscribe path) — e.g. callemitContactEvent(contact, "contact.updated", teamId)after the update, or route the change through the existing updateContactInContactBook so the event fires in one place.

Replication Steps

Steps to reproduce

  1. Register a webhook subscribed to contact.updated.
  2. Unsubscribe a contact via the campaign email link (or the one-click header).
  3. No webhook is delivered, although contact.subscribed changed to false.

Expected

Unsubscribing (and re-subscribing) a contact should emit contact.updated, consistent with updateContactInContactBook.

Actual

No event emitted; the subscription change is invisible to webhook consumers.

Self hosted or Cloud?

Self hosted

What browsers are you seeing the problem on?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions