A bidirectional webhook integration that syncs opportunities from Twenty CRM with projects in Linear, keeping your sales pipeline and project management in perfect harmony.
- Automatic Project Creation: When an opportunity reaches
CLOSED_WONin Twenty, a corresponding project is automatically created in Linear - Bidirectional Sync: Changes in Linear projects sync back to Twenty opportunities
- Status Mapping: Intelligent mapping between Linear project states and Twenty delivery statuses
- Progress Tracking: Automatic calculation of project progress based on Linear issue completion
- Secure Webhooks: Cryptographic signature verification for both Twenty and Linear webhooks
- Node.js (v14 or higher)
- npm or yarn
- A Twenty workspace with API access
- A Linear workspace with API access
- A publicly accessible server (or tunneling solution for development)
git clone https://github.com/bobbyy16/twenty-linear-integration.git
cd twenty-linear-integrationnpm installCreate a .env file in the root directory with the following variables:
TWENTY_API_KEY=your_20_api_key
TWENTY_BASE_URL=https://your-workspace.twenty.com
TWENTY_WEBHOOK_SECRET=your_twenty_webhook_secret
LINEAR_API_KEY=your_linear_api_key
LINEAR_TEAM_ID=your_linear_team_id
LINEAR_WEBHOOK_SECRET=your_linear_webhook_secret
PORT=8080In Twenty:
- Configure your webhook URL to
https://<your-domain>/webhooks/twenty - Supply your
TWENTY_WEBHOOK_SECRET
In Linear:
- Configure your webhook URL to
https://<your-domain>/webhooks/linear - Supply your
LINEAR_WEBHOOK_SECRET(if applicable)
Ensure your server is reachable (public URL or via tunneling for dev).
npm startThe server listens on the value of PORT (default 8080).
/health– Simple health check/webhooks/twenty– Handle Twenty webhooks/webhooks/linear– Handle Linear webhooks
- Opportunity in Twenty moves to stage
CLOSED_WON - This triggers the webhook
- The middleware
validateTwentyWebhookconfirms the signature twentyService.handleOpportunityUpdate()creates a new project in Linear (vialinearApi.createProject)- It then updates the Twenty opportunity with:
linearprojectidprojectProgress=0deliverystatus=INITIATEDsyncstatus=SYNCED
- A project in Linear updates (e.g., status changes or issue progress)
- The webhook on
/webhooks/lineartriggerslinearService.handleProjectUpdate()orhandleIssueUpdate() - The sync service finds the linked Twenty opportunity (
extractTwentyIdFromLinear(), which reads the Linear project description for[TwentyOpportunityId: …]) - It builds a payload mapping Linear status → Twenty fields (
deliverystatus,projectprogress,closeDate, etc.) - It calls
twentyApi.updateOpportunity()to update the record in Twenty
config/fieldMappings.js holds all field-name mappings and enums (Twenty field names, delivery status values, sync status values).
| Linear State | Progress | Delivery Status |
|---|---|---|
| backlog | 0% | INITIATED |
| planned | 10% | INITIATED |
| in progress / started | 40% | IN_PROGRESS |
| completed / done / finished | 100% | DELIVERED |
| canceled / cancelled / archived | 0% | CANCELLED |
Ensure the custom fields in Twenty match the internal API names and types:
linearprojectid– Text field for Linear project IDprojectprogress– Number/decimal field for progress (0-1 or 0-100)deliverystatus– Select field with values: INITIATED, IN_PROGRESS, DELIVERED, CANCELLEDsyncstatus– Select field with values: SYNCED, PENDING, ERROR
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add some feature') - Push to the branch (
git push origin feature/my-feature) - Submit a Pull Request
Feel free to open issues for bugs or enhancements.
This project is licensed under the MIT License.
Thanks to the teams behind the Twenty API and Linear API for enabling these integrations.
Inspired by the need to keep CRM data and project tracking in sync with minimal manual effort.