From 25a9d49ff172dc42535752015dbd8e2b4bc6f9fe Mon Sep 17 00:00:00 2001 From: StephanieJoly4 Date: Tue, 13 Jan 2026 23:49:51 +0100 Subject: [PATCH] New article to detail how to attach pdf files to a given record (#17128) - added article to detail how to attach a pdf to a given record - added link in another article - updated the english section of the docs.json to have the file appear in the left menu - updated the 2 navigation files --------- Co-authored-by: github-actions --- packages/twenty-docs/docs.json | 42 ++-- .../navigation/base-structure.json | 3 +- .../navigation/navigation-schema.json | 3 +- .../generate-pdf-from-twenty.mdx | 227 ++++++++++++++++++ .../generate-quote-or-invoice-from-twenty.mdx | 1 + 5 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 packages/twenty-docs/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty.mdx 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)