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 <github-actions@twenty.com>
This commit is contained in:
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+227
@@ -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**)
|
||||
|
||||
<Tip>
|
||||
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.
|
||||
</Tip>
|
||||
|
||||
### 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}}` |
|
||||
|
||||
<Note>
|
||||
If attaching to a different object (Person, Opportunity, etc.), rename the parameter accordingly (e.g., `personId`, `opportunityId`) and update the serverless function.
|
||||
</Note>
|
||||
|
||||
#### 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)
|
||||
|
||||
+1
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user