diff --git a/packages/twenty-docs/docs.json b/packages/twenty-docs/docs.json
index bfb26cb873..0b7494558a 100644
--- a/packages/twenty-docs/docs.json
+++ b/packages/twenty-docs/docs.json
@@ -183,7 +183,8 @@
"user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -624,7 +625,8 @@
"l/fr/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/fr/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/fr/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/fr/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/fr/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/fr/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -1065,7 +1067,8 @@
"l/ar/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/ar/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/ar/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/ar/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/ar/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/ar/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -1506,7 +1509,8 @@
"l/cs/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/cs/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/cs/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/cs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/cs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/cs/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -1947,7 +1951,8 @@
"l/de/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/de/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/de/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/de/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/de/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/de/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -2388,7 +2393,8 @@
"l/es/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/es/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/es/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/es/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/es/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/es/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -2829,7 +2835,8 @@
"l/it/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/it/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/it/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/it/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/it/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/it/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -3270,7 +3277,8 @@
"l/ja/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/ja/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/ja/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/ja/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/ja/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/ja/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -3711,7 +3719,8 @@
"l/ko/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/ko/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/ko/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/ko/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/ko/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/ko/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -4152,7 +4161,8 @@
"l/pt/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/pt/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/pt/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/pt/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/pt/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/pt/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -4593,7 +4603,8 @@
"l/ro/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/ro/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/ro/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/ro/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/ro/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/ro/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -5034,7 +5045,8 @@
"l/ru/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/ru/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/ru/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/ru/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/ru/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/ru/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -5475,7 +5487,8 @@
"l/tr/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/tr/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/tr/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/tr/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/tr/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/tr/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
@@ -5916,7 +5929,8 @@
"l/zh/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"l/zh/user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"l/zh/user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "l/zh/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "l/zh/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "l/zh/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
diff --git a/packages/twenty-docs/navigation/base-structure.json b/packages/twenty-docs/navigation/base-structure.json
index 790982463a..2fd73b6e46 100644
--- a/packages/twenty-docs/navigation/base-structure.json
+++ b/packages/twenty-docs/navigation/base-structure.json
@@ -166,7 +166,8 @@
"user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
diff --git a/packages/twenty-docs/navigation/navigation-schema.json b/packages/twenty-docs/navigation/navigation-schema.json
index 790982463a..2fd73b6e46 100644
--- a/packages/twenty-docs/navigation/navigation-schema.json
+++ b/packages/twenty-docs/navigation/navigation-schema.json
@@ -166,7 +166,8 @@
"user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-typeform-submissions-in-twenty",
"user-guide/workflows/how-tos/connect-to-other-tools/bring-product-data-in-twenty",
- "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty"
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty",
+ "user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty"
]
},
{
diff --git a/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty.mdx b/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty.mdx
new file mode 100644
index 0000000000..df001353ed
--- /dev/null
+++ b/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty.mdx
@@ -0,0 +1,227 @@
+---
+title: Generate a PDF from Twenty
+description: Create a workflow to generate and attach a PDF (such as a quote) to a record.
+---
+
+Automatically generate or fetch a PDF and attach it to a record in Twenty. This is commonly used to create quotes, invoices, or reports that are linked to Companies, Opportunities, or other objects.
+
+## Overview
+
+This workflow uses a **Manual Trigger** so users can generate a PDF on demand for any selected record. A **Serverless Function** handles:
+1. Downloading the PDF from a URL (from a PDF generation service)
+2. Uploading the file to Twenty
+3. Creating an Attachment linked to the record
+
+## Prerequisites
+
+Before setting up the workflow:
+
+1. **Create an API Key**: Go to **Settings → APIs** and create a new API key. You'll need this token for the serverless function.
+2. **Set up a PDF generation service** (optional): If you want to dynamically generate PDFs (e.g., quotes), use a service like Carbone, PDFMonkey, or DocuSeal to create the PDF and get a download URL.
+
+## Step-by-Step Setup
+
+### Step 1: Configure the Trigger
+
+1. Go to **Workflows** and create a new workflow
+2. Select **Manual Trigger**
+3. Choose the object you want to attach PDFs to (e.g., **Company** or **Opportunity**)
+
+
+With a Manual Trigger, users can run this workflow using a button that appears on the top right once a record is selected, to generate and attach a PDF.
+
+
+### Step 2: Add a Serverless Function
+
+1. Add a **Serverless Function** action
+2. Create a new function with the code below
+3. Configure the input parameters
+
+#### Input Parameters
+
+| Parameter | Value |
+|-----------|-------|
+| `companyId` | `{{trigger.object.id}}` |
+
+
+If attaching to a different object (Person, Opportunity, etc.), rename the parameter accordingly (e.g., `personId`, `opportunityId`) and update the serverless function.
+
+
+#### Serverless Function Code
+
+```typescript
+export const main = async (
+ params: { companyId: string },
+) => {
+ const { companyId } = params;
+
+ // Replace with your Twenty GraphQL endpoint
+ // Cloud: https://api.twenty.com/graphql
+ // Self-hosted: https://your-domain.com/graphql
+ const graphqlEndpoint = 'https://api.twenty.com/graphql';
+
+ // Replace with your API key from Settings → APIs
+ const authToken = 'YOUR_API_KEY';
+
+ // Replace with your PDF URL
+ // This could be from a PDF generation service or a static URL
+ const pdfUrl = 'https://your-pdf-service.com/generated-quote.pdf';
+ const filename = 'quote.pdf';
+
+ // Step 1: Download the PDF file
+ const pdfResponse = await fetch(pdfUrl);
+
+ if (!pdfResponse.ok) {
+ throw new Error(`Failed to download PDF: ${pdfResponse.status}`);
+ }
+
+ const pdfBlob = await pdfResponse.blob();
+ const pdfFile = new File([pdfBlob], filename, { type: 'application/pdf' });
+
+ // Step 2: Upload the file via GraphQL multipart upload
+ const uploadMutation = `
+ mutation UploadFile($file: Upload!, $fileFolder: FileFolder) {
+ uploadFile(file: $file, fileFolder: $fileFolder) {
+ path
+ }
+ }
+ `;
+
+ const uploadForm = new FormData();
+ uploadForm.append('operations', JSON.stringify({
+ query: uploadMutation,
+ variables: { file: null, fileFolder: 'Attachment' },
+ }));
+ uploadForm.append('map', JSON.stringify({ '0': ['variables.file'] }));
+ uploadForm.append('0', pdfFile);
+
+ const uploadResponse = await fetch(graphqlEndpoint, {
+ method: 'POST',
+ headers: { Authorization: `Bearer ${authToken}` },
+ body: uploadForm,
+ });
+
+ const uploadResult = await uploadResponse.json();
+
+ if (uploadResult.errors?.length) {
+ throw new Error(`Upload failed: ${uploadResult.errors[0].message}`);
+ }
+
+ const filePath = uploadResult.data?.uploadFile?.path;
+
+ if (!filePath) {
+ throw new Error('No file path returned from upload');
+ }
+
+ // Step 3: Create the attachment linked to the company
+ const attachmentMutation = `
+ mutation CreateAttachment($data: AttachmentCreateInput!) {
+ createAttachment(data: $data) {
+ id
+ name
+ }
+ }
+ `;
+
+ const attachmentResponse = await fetch(graphqlEndpoint, {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${authToken}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ query: attachmentMutation,
+ variables: {
+ data: {
+ name: filename,
+ fullPath: filePath,
+ companyId,
+ },
+ },
+ }),
+ });
+
+ const attachmentResult = await attachmentResponse.json();
+
+ if (attachmentResult.errors?.length) {
+ throw new Error(`Attachment creation failed: ${attachmentResult.errors[0].message}`);
+ }
+
+ return attachmentResult.data?.createAttachment;
+};
+```
+
+### Step 3: Customize for Your Use Case
+
+#### To attach to a different object
+
+Replace `companyId` with the appropriate field:
+
+| Object | Field Name |
+|--------|------------|
+| Company | `companyId` |
+| Person | `personId` |
+| Opportunity | `opportunityId` |
+| Custom Object | `yourCustomObjectId` |
+
+Update both the function parameter and the `variables.data` object in the attachment mutation.
+
+#### To use a dynamic PDF URL
+
+If using a PDF generation service, you can:
+1. First make an HTTP Request action to generate the PDF
+2. Pass the returned PDF URL to the serverless function as a parameter
+
+```typescript
+export const main = async (
+ params: { companyId: string; pdfUrl: string; filename: string },
+) => {
+ const { companyId, pdfUrl, filename } = params;
+ // ... rest of the function
+};
+```
+
+### Step 4: Test and Activate
+
+1. Save the workflow
+2. Navigate to a Company record
+3. Click the **⋮** menu and select your workflow
+4. Check the **Attachments** section on the record to verify the PDF was attached
+5. Activate the workflow
+
+## Combining with PDF Generation Services
+
+For creating dynamic quotes or invoices:
+
+### Example: Generate Quote → Attach PDF
+
+| Step | Action | Purpose |
+|------|--------|---------|
+| 1 | Manual Trigger (Company) | User initiates on a record |
+| 2 | Search Record | Get Opportunity or line item details |
+| 3 | HTTP Request | Call PDF generation API with record data |
+| 4 | Serverless Function | Download and attach the generated PDF |
+
+### Popular PDF Generation Services
+
+- **Carbone** - Template-based document generation
+- **PDFMonkey** - Dynamic PDF creation from templates
+- **DocuSeal** - Document automation platform
+- **Documint** - API-first document generation
+
+Each service provides an API that returns a PDF URL, which you can then pass to the serverless function.
+
+## Troubleshooting
+
+| Issue | Solution |
+|-------|----------|
+| "Failed to download PDF" | Check the PDF URL is accessible and returns a valid PDF |
+| "Upload failed" | Verify your API key is valid and has write permissions |
+| "Attachment creation failed" | Ensure the object ID field name matches your target object |
+
+## Related
+
+- [Workflow Triggers](/user-guide/workflows/capabilities/workflow-triggers)
+- [Serverless Functions](/user-guide/workflows/capabilities/workflow-actions#serverless-function)
+- [Generate a Quote or Invoice from Twenty](/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty)
+
diff --git a/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty.mdx b/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty.mdx
index c6f433d258..daf8ac950e 100644
--- a/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty.mdx
+++ b/packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty.mdx
@@ -138,6 +138,7 @@ Body: {{code.invoice}}
## Related
+- [Generate a PDF from Twenty](/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty) — attach generated PDFs to records
- [Workflow Triggers](/user-guide/workflows/capabilities/workflow-triggers)
- [Workflow Actions](/user-guide/workflows/capabilities/workflow-actions)
- [Closed Won Automations](/user-guide/workflows/how-tos/crm-automations/closed-won-automations)