packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty.mdx
Automatically send deal data to your invoicing system (Stripe, QuickBooks, Xero, etc.) when an opportunity is won.
Add a Filter action to only continue when the deal is won:
| Setting | Value |
|---|---|
| Field | Stage |
| Condition | Equals |
| Value | CLOSED_WON (or your stage name) |
The Opportunity record may not include all Company fields you need for the invoice. Add a Search Record action:
| Setting | Value |
|---|---|
| Object | Company |
| Match by | ID equals {{trigger.object.companyId}} |
This retrieves the full Company record with billing address, tax ID, etc.
If your invoicing system expects a specific format, add a Code action:
export const main = async (params: {
opportunity: any;
company: any;
}): Promise<object> => {
const { opportunity, company } = params;
return {
invoice: {
// Customer info from Company
customer_name: company.name,
customer_email: company.email || "",
billing_address: {
line1: company.address?.street || "",
city: company.address?.city || "",
postal_code: company.address?.postalCode || "",
country: company.address?.country || ""
},
tax_id: company.taxId || null,
// Invoice details from Opportunity
amount: opportunity.amount,
currency: opportunity.currency || "USD",
description: `Invoice for ${opportunity.name}`,
due_days: 30,
// Reference back to Twenty
metadata: {
opportunity_id: opportunity.id,
company_id: company.id
}
}
};
};
Add an HTTP Request action:
| Setting | Value |
|---|---|
| Method | POST |
| URL | Your invoicing API endpoint |
| Headers | Authorization: Bearer YOUR_API_KEY |
| Body | {{code.invoice}} or map fields directly |
POST https://api.stripe.com/v1/invoices
Headers:
Authorization: Bearer sk_live_xxx
Content-Type: application/x-www-form-urlencoded
Body:
customer: {{company.stripeCustomerId}}
collection_method: send_invoice
days_until_due: 30
POST https://quickbooks.api.intuit.com/v3/company/{realmId}/invoice
Headers:
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Body: {{code.invoice}}
| Step | Action | Purpose |
|---|---|---|
| 1 | Trigger: Record Updated | Fires when any Opportunity changes |
| 2 | Filter | Only proceed if Stage = Closed Won |
| 3 | Search Record | Get full Company details for billing |
| 4 | Code | Format data for invoicing API |
| 5 | HTTP Request | Create invoice in external system |