Twenty is the open-source CRM built for developers. Learn how to trigger Workify invoice creation directly from Twenty's webhook system when opportunities are won.
A direct webhook integration between Twenty CRM and Workify. When an opportunity in Twenty is moved to Won, Twenty fires a webhook that creates a Workify invoice — no third-party automation platform required.
Twenty is an open-source CRM (think Salesforce, but self-hosted and developer-friendly) with a GraphQL API and a clean webhook system. Workify exposes a REST API. Both are built for developers who want control over their tooling without vendor lock-in. Connecting them is a natural fit.
Settings → API Keys)Twenty fires webhooks for object mutations. You can subscribe to events like:
opportunity.createdopportunity.updatedperson.createdEach webhook delivers a JSON payload with the changed object and its fields. You'll listen for opportunity.updated and filter for when stage = WON.
In Workify, go to Settings → API Keys, create a key named "Twenty CRM", and grant invoices:write and clients:read (and optionally clients:write) scopes.
In Twenty's settings (or via the API), create a webhook subscription:
Via Twenty UI: Settings → Webhooks → Add webhook
Via Twenty API (GraphQL):
mutation {
createWebhook(data: {
targetUrl: "https://your-worker.your-domain.workers.dev/workify"
operation: "opportunity.updated"
}) {
id
targetUrl
}
}
Point targetUrl at your serverless function endpoint.
Twenty and Workify speak different schemas, so a small transform is needed. Here's a Cloudflare Worker that handles the conversion:
export default {
async fetch(request: Request): Promise<Response> {
const payload = await request.json() as any
// Only act on opportunity Won events
if (payload.objectMetadata?.nameSingular !== 'opportunity') return new Response('ok')
if (payload.record?.stage !== 'WON') return new Response('ok')
const opp = payload.record
// Look up the Workify client by email
const clientRes = await fetch(
`https://getworkify.app/api/v1/clients?email=${opp.pointOfContact?.email}`,
{ headers: { Authorization: `Bearer ${env.WORKIFY_API_KEY}` } }
)
const clients = await clientRes.json() as any
const clientId = clients.data?.[0]?.id
if (!clientId) {
console.error('No Workify client found for', opp.pointOfContact?.email)
return new Response('client not found', { status: 404 })
}
// Create the invoice
const invoiceRes = await fetch('https://getworkify.app/api/v1/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${env.WORKIFY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
org_id: env.WORKIFY_ORG_ID,
client_id: clientId,
currency: 'GBP',
notes: `Re: ${opp.name}`,
line_items: [{
description: opp.name,
quantity: 1,
unit_price: (opp.amount?.amountMicros ?? 0) / 1000000,
}],
due_date: new Date(Date.now() + 30 * 86400000).toISOString().split('T')[0],
}),
})
const invoice = await invoiceRes.json()
console.log('Created invoice', invoice)
return new Response('ok')
}
}
Set WORKIFY_API_KEY and WORKIFY_ORG_ID as environment variables/secrets in your worker.
Note on amounts: Twenty stores monetary values in
amountMicros(millionths of the currency unit). Divide by 1,000,000 to get the major unit value for Workify'sunit_price(e.g.1500000000amountMicros →1500= £1,500).
Deploy your worker:
wrangler deploy
In Twenty, move a test opportunity to Won and check your worker logs. A Workify invoice should appear as a draft within seconds.
Close the loop by updating the Twenty opportunity with the Workify invoice ID after creation. Add to your worker after the invoice is created:
await fetch(`https://api.twenty.com/objects/opportunities/${opp.id}`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${env.TWENTY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
// Requires a custom field in Twenty — add via Settings → Objects → Opportunities
workifyInvoiceId: invoice.id,
}),
})
If you prefer not to write code, use Make or n8n as middleware:
Both work well; the serverless approach is faster and removes a dependency on a third-party platform.
workifyInvoiceId field to Opportunity objects for the write-backx-twenty-webhook-signature header in your worker before processingGet your Workify API key and start building in minutes. Pro plan includes full API and webhook access.