packages/twenty-apps/internal/twenty-for-twenty/README.md
This is a Twenty application bootstrapped with create-twenty-app.
Twenty for Twenty is the official internal Twenty app. It is organized into modules, each integrating a third-party service with Twenty.
src/modules/resend/)Two-way sync between Twenty and the Resend email platform. The module syncs contacts, segments, templates, broadcasts, and emails.
Inbound (Resend -> Twenty):
Outbound (Twenty -> Resend):
yarn twenty dev
This registers the app with your local Twenty instance at http://localhost:3000/settings/applications.
In Twenty, go to Settings > Applications > Twenty for Twenty and set:
The app exposes an HTTP endpoint at /s/webhook/resend that receives Resend webhook events. To connect it:
/s/webhook/resend (e.g. https://your-domain.com/s/webhook/resend)RESEND_WEBHOOK_SECRET app variable in TwentyThe webhook handles:
contact.created, contact.updated, contact.deleted) -- upserts/deletes Resend contact records in Twentyemail.sent, email.delivered, email.bounced, email.opened, email.clicked, etc.) -- updates delivery status on Resend email records in real-timeInstall the Resend CLI:
brew install resend/cli/resend
Or via npm if Homebrew has issues:
npm install -g resend-cli
Authenticate:
resend login
Start the webhook listener with forwarding to your local Twenty server:
resend webhooks listen --forward-to http://localhost:3000/s/webhook/resend
The CLI will:
To trigger test events, create or update a contact in the Resend dashboard, or send a test email.
| Source | Mechanism | Entities |
|---|---|---|
| Cron (every 5 min) | Polls Resend API, upserts into Twenty | Contacts, segments, templates, broadcasts, emails |
| Webhook (real-time) | Receives Resend events via HTTP | Contacts, emails |
| Twenty action | Resend API call |
|---|---|
| Create contact | contacts.create() -- writes resendId back to Twenty |
| Update contact (name, email, unsubscribed) | contacts.update() |
| Delete contact | contacts.remove() |
| Create segment | segments.create() -- writes resendId back to Twenty |
| Delete segment | segments.remove() |
A lastSyncedFromResend field on contact, segment, and email records tracks when data came from Resend. Outbound triggers skip processing when this field is part of the update, preventing infinite echo loops between inbound and outbound sync.
Run yarn twenty help to list all available commands.