Documentation Index Fetch the complete documentation index at: https://docs.langdock.com/llms.txt
Use this file to discover all available pages before exploring further.
File inputs allow users to upload files that your action can then process or send to external APIs.
Upload files to external tools : Send user-uploaded documents to APIs, cloud storage, or external services like email or tickets systems.
Process user files : Analyze, convert, or transform files uploaded by users
Add an input field of type “FILE” to accept one file
For multiple files, enable Allow multiple files :
1.3 Accessing File Data in Code
Every uploaded file is delivered as a FileData object with this exact format:
{
fileName : "Invoice.pdf" ,
mimeType : "application/pdf" ,
size : 102400 , // bytes
base64 : "JVBERi0xLjQK..." , // binary content, Base64-encoded
lastModified : "2024-01-15T10:30:00Z" // ISO date string
}
Important : File inputs do NOT include a text property. The text shortcut only exists for file outputs.
Single File Access
// 'document' in this example is the id of the created input field
const document = data . input . document ; // FileData object
const buffer = Buffer . from ( document . base64 , "base64" );
ld . log ( `Processing ${ document . fileName } ( ${ document . size } bytes)` );
Multiple Files Access
// 'attachments' in this example is the id of the created input field
const files = data . input . attachments ; // FileData[] array
for ( const file of files ) {
const buffer = Buffer . from ( file . base64 , "base64" );
await processFile ( buffer , file . mimeType );
}
Data Structure : When “Allow multiple files” is enabled, data.input.fieldName is an array. Otherwise, it’s a single object.
Show Email with Attachments
// Gmail-style email with file attachments
const recipient = data . input . mailRecipient ;
const subject = data . input . mailSubject ;
const body = data . input . mailBody ;
const attachments = data . input . attachments || [];
// Build multipart email
let email = `To: ${ recipient } \r\n Subject: ${ subject } \r\n ` ;
if ( attachments . length > 0 ) {
const boundary = `boundary_ ${ Date . now () } ` ;
email += `Content-Type: multipart/mixed; boundary=" ${ boundary } " \r\n\r\n ` ;
email += `-- ${ boundary } \r\n Content-Type: text/html \r\n\r\n ${ body } \r\n ` ;
// Add each attachment
for ( const attachment of attachments ) {
email += `-- ${ boundary } \r\n ` ;
email += `Content-Type: ${ attachment . mimeType } \r\n ` ;
email += `Content-Transfer-Encoding: base64 \r\n ` ;
email += `Content-Disposition: attachment; filename=" ${ attachment . fileName } " \r\n ` ;
email += ` \r\n ${ attachment . base64 } \r\n ` ;
}
email += `-- ${ boundary } --` ;
}
Show Document Upload to API
const document = data . input . document ;
// Validate file type
if ( ! document . mimeType . startsWith ( 'application/pdf' )) {
throw new Error ( 'Only PDF files are supported' );
}
try {
const response = await ld . request ({
method: 'POST' ,
url: 'https://api.example.com/documents' ,
headers: {
'Authorization' : `Bearer ${ data . auth . apiKey } ` ,
'Content-Type' : 'application/json'
},
body: {
filename: document . fileName ,
content: document . base64 ,
mimeType: document . mimeType
}
});
return {
success: true ,
documentId: response . json . id ,
message: `Uploaded ${ document . fileName } successfully`
};
} catch ( error ) {
return {
success: false ,
error: `Failed to upload ${ document . fileName } : ${ error . message } `
};
}
Show Batch File Processing
const files = data . input . files || [];
if ( files . length === 0 ) {
return { error: 'No files provided' };
}
const results = [];
for ( const file of files ) {
try {
const buffer = Buffer . from ( file . base64 , 'base64' );
// Process based on file type
let result ;
if ( file . mimeType . startsWith ( 'image/' )) {
result = await processImage ( buffer );
} else if ( file . mimeType === 'application/pdf' ) {
result = await processPDF ( buffer );
} else {
throw new Error ( `Unsupported file type: ${ file . mimeType } ` );
}
results . push ({
filename: file . fileName ,
status: 'success' ,
result: result
});
ld . log ( `Processed ${ file . fileName } successfully` );
} catch ( error ) {
results . push ({
filename: file . fileName ,
status: 'error' ,
error: error . message
});
ld . log ( `Failed to process ${ file . fileName } : ${ error . message } ` );
}
}
return {
success: true ,
processed: results . filter ( r => r . status === 'success' ). length ,
failed: results . filter ( r => r . status === 'error' ). length ,
results: results
};
// Validate file presence
const files = data . input . attachments ;
if ( ! files || files . length === 0 ) {
return { error: "No files provided. Please attach at least one file." };
}
// Validate file types
const allowedTypes = [ "application/pdf" , "image/jpeg" , "image/png" ];
for ( const file of files ) {
if ( ! allowedTypes . includes ( file . mimeType )) {
return {
error: `Unsupported file type: ${
file . mimeType
} . Allowed: ${ allowedTypes . join ( ", " ) } ` ,
};
}
}
// Log file metadata for debugging
ld . log (
"Processing files:" ,
files . map (( f ) => ({
fileName: f . fileName ,
mimeType: f . mimeType ,
size: f . size ,
}))
);
2. File Output in Actions
File outputs allow your action to generate and return files that users can download or use in subsequent actions.
2.1 When to Use File Outputs
Generate reports : Create PDFs, spreadsheets, or documents from data
Retrieve files from APIs : Download files from external services
Transform files : Convert between formats or process uploaded files
Export data : Create CSV exports, backup files, or data dumps
Return files under a files key in your response:
// Single file output
return {
files: {
fileName: "report.pdf" ,
mimeType: "application/pdf" ,
base64: "JVBERi0xLjQK..." , // Base64 encoded content
},
};
// Multiple files output
return {
files: [
{
fileName: "data.csv" ,
mimeType: "text/csv" ,
text: "Name,Email \n John,john@example.com" , // Text shortcut for UTF-8
},
{
fileName: "chart.png" ,
mimeType: "image/png" ,
base64: "iVBORw0KGgoAAAANSUhEUgAA..." ,
},
],
};
File Output Properties
Field Required Notes fileName✓ Include proper file extension mimeType✓ Accurate MIME type for proper handling base64✓* Base64 encoded binary content text✓* UTF-8 text content (alternative to base64) lastModified– ISO date string (defaults to current time)
*Provide either base64 OR text, never both.
2.3 Common Output Patterns
// Generate a PDF report from data
const reportData = await fetchReportData ();
// Create PDF content (using custom built function / endpoint)
const pdfBuffer = await generatePDF ({
title: 'Monthly Report' ,
data: reportData ,
template: 'standard'
});
return {
files: {
fileName: `monthly-report- ${ new Date (). toISOString (). slice ( 0 , 7 ) } .pdf` ,
mimeType: 'application/pdf' ,
base64: pdfBuffer . toString ( 'base64' )
},
success: true ,
message: `Generated report with ${ reportData . length } entries`
};
// Export data as CSV using text shortcut
const customers = await fetchCustomers ();
// Build CSV content
const csvHeader = 'Name,Email,Created,Status' ;
const csvRows = customers . map ( c =>
`" ${ c . name } "," ${ c . email } "," ${ c . created } "," ${ c . status } "`
);
const csvContent = [ csvHeader , ... csvRows ]. join ( ' \n ' );
return {
files: {
fileName: `customers-export- ${ new Date (). toISOString (). slice ( 0 , 10 ) } .csv` ,
mimeType: 'text/csv' ,
text: csvContent // Use text for UTF-8 content
},
success: true ,
exported: customers . length
};
Show Download File from API
// Download file from external API
const fileId = data . input . fileId ;
try {
const response = await ld . request ({
method: 'GET' ,
url: `https://api.example.com/files/ ${ fileId } ` ,
headers: {
'Authorization' : `Bearer ${ data . auth . apiKey } `
},
responseType: 'stream'
});
// Get filename from response headers or API
const filename = response . headers [ 'content-disposition' ]
?. match ( /filename=" ( . + ) "/ )?.[ 1 ] || `file- ${ fileId } ` ;
return {
files: {
fileName: filename ,
mimeType: response . headers [ 'content-type' ] || 'application/octet-stream' ,
base64: Buffer . from ( response . buffer ). toString ( 'base64' )
},
success: true ,
message: `Downloaded ${ filename } `
};
} catch ( error ) {
return {
success: false ,
error: `Failed to download file: ${ error . message } `
};
}
Show Process and Return Multiple Files
// Process input files and return modified versions
const inputFiles = data . input . documents || [];
const outputFiles = [];
for ( const file of inputFiles ) {
try {
const buffer = Buffer . from ( file . base64 , 'base64' );
// Process file (e.g., compress, convert, etc.)
const processedBuffer = await processFile ( buffer , file . mimeType );
outputFiles . push ({
fileName: `processed- ${ file . fileName } ` ,
mimeType: file . mimeType ,
base64: processedBuffer . toString ( 'base64' )
});
} catch ( error ) {
ld . log ( `Failed to process ${ file . fileName } : ${ error . message } ` );
}
}
return {
files: outputFiles ,
success: true ,
processed: outputFiles . length ,
message: `Processed ${ outputFiles . length } of ${ inputFiles . length } files`
};
3. File Output in Triggers
Triggers can also return files when detecting events that include file attachments or when generating files based on trigger data.
Key Difference : Unlike actions that return objects directly, triggers must return an array of events. Each event needs id, timestamp, and data properties, with files inside the data object.
3.1 When to Use File Outputs in Triggers
Email attachments : Forward attachments from incoming emails
File change events : Return modified or new files from monitored systems
Generated notifications : Create summary files or reports when events occur
API webhook files : Process and forward files from webhook payloads
Triggers must return an array of objects with id, timestamp, and data properties. Files go inside the data object:
// Required trigger format with files
return [
{
id: "msg_123" , // Unique identifier for this event
timestamp: "2024-01-15T10:30:00Z" , // Event timestamp
data: {
from: "sender@example.com" ,
subject: "Invoice #12345" ,
body: "Please find the invoice attached." ,
messageId: "msg_123" ,
files: [
// Files go INSIDE data object
{
fileName: "invoice-12345.pdf" ,
mimeType: "application/pdf" ,
base64: "JVBERi0xLjQK..." ,
},
],
},
},
];
Important : Unlike actions, triggers must return an array of events, and files must be inside the data object, not at the top level.
3.3 Common Trigger Patterns
Show Email Trigger with Attachments
// Gmail trigger processing incoming emails
const emails = await fetchNewEmails ();
const results = [];
for ( const email of emails ) {
const attachments = [];
// Process email attachments if any
if ( email . attachments && email . attachments . length > 0 ) {
for ( const attachment of email . attachments ) {
// Download attachment content
const content = await downloadAttachment ( attachment . id );
attachments . push ({
fileName: attachment . filename ,
mimeType: attachment . mimeType ,
base64: content . toString ( 'base64' )
});
}
}
results . push ({
id: email . id , // Required: unique event ID
timestamp: email . date , // Required: event timestamp
data: {
from: email . from ,
subject: email . subject ,
body: email . body ,
receivedAt: email . date ,
messageId: email . id ,
threadId: email . threadId ,
files: attachments // Files inside data object
}
});
}
return results ; // Return array of trigger events
// Monitor for new files in a directory
const newFiles = await checkForNewFiles ( data . input . directory );
const results = [];
for ( const file of newFiles ) {
try {
// Download file content
const content = await downloadFile ( file . path );
results . push ({
id: file . id || file . path , // Required: unique file identifier
timestamp: file . lastModified , // Required: event timestamp
data: {
filePath: file . path ,
fileName: file . name ,
size: file . size ,
modifiedAt: file . lastModified ,
event: 'file_created' ,
files: [ // Files array inside data object
{
fileName: file . name ,
mimeType: file . mimeType || 'application/octet-stream' ,
base64: content . toString ( 'base64' )
}
]
}
});
} catch ( error ) {
ld . log ( `Failed to process file ${ file . name } : ${ error . message } ` );
}
}
return results ; // Return array of trigger events
Constraint Limit Total file size per action 100 MB Maximum files per action 20 files Individual documents ≤ 256 MB* Individual images ≤ 20 MB Individual spreadsheets ≤ 30 MB Individual audio files ≤ 200 MB* Individual video files ≤ 20 MB Other file types ≤ 256 MB* Action execution timeout 2 minutes
*Still bounded by the 100 MB total limit.
Validation : Exceeding limits throws an error before your code executes .
{
"error" : "Total file size (120.0 MB) exceeds the action execution limit of 100.0 MB. Please use smaller files or reduce the number of files."
}
4.1 Sandbox Library Restrictions
Custom action and trigger code runs in a secure sandboxed environment.
You cannot install or import external libraries (npm, pip, etc.) - only a limited set of built-in JavaScript/Node.js APIs are available.
For advanced file processing (e.g., PDF parsing, image manipulation), use external APIs or services and call them from your code.
5. Best Practices
Validate file types early : Check MIME types before processing
Handle missing files gracefully : Use || [] for optional file arrays
Log file metadata : Help debug issues without exposing content
Provide clear error messages : Tell users exactly what went wrong
// Good validation pattern
const files = data . input . attachments || [];
if ( files . length === 0 ) {
return { error: "Please attach at least one file to process." };
}
const allowedTypes = [ "image/jpeg" , "image/png" , "application/pdf" ];
for ( const file of files ) {
if ( ! allowedTypes . includes ( file . mimeType )) {
return {
error: `File " ${ file . fileName } " has unsupported type ${
file . mimeType
} . Allowed: ${ allowedTypes . join ( ", " ) } ` ,
};
}
}
File Output Best Practices
Use meaningful filenames : Include dates, IDs, or descriptive names
Set accurate MIME types : Enables proper file handling and previews
Use text shortcut for UTF-8 : More efficient than base64 for text files
Include processing status : Help users understand what happened
// Good output pattern
return {
files: {
fileName: `customer-report- ${ new Date (). toISOString (). slice ( 0 , 10 ) } .pdf` ,
mimeType: "application/pdf" ,
base64: reportBuffer . toString ( "base64" ),
},
success: true ,
recordsProcessed: customerData . length ,
message: `Generated report with ${ customerData . length } customer records` ,
};
Process files in parallel when possible : Use Promise.all() for independent operations
Avoid loading all files into memory : Process one at a time for large batches
Log progress : Use ld.log() to track processing status
Handle errors gracefully : Continue processing other files if one fails
// Good error handling pattern
const results = [];
for ( const file of files ) {
try {
const result = await processFile ( file );
results . push ({ fileName: file . fileName , status: "success" , result });
ld . log ( `✓ Processed ${ file . fileName } ` );
} catch ( error ) {
results . push ({
fileName: file . fileName ,
status: "error" ,
error: error . message ,
});
ld . log ( `✗ Failed ${ file . fileName } : ${ error . message } ` );
}
}
6. Troubleshooting
Issue Likely Cause Solution ”File not found” User didn’t attach file Make file input required or add validation Size limit error Files exceed 100 MB total Ask for smaller files or fewer files ”Invalid file type” Wrong MIME type Validate file.mimeType in your code Empty file content Base64 encoding issue Verify file.base64 is valid Timeout errors Large files or slow processing Optimize processing or reduce file sizes Memory errors Too many large files Process files sequentially, not in parallel
Debug Helper
// Safe logging for file metadata (never logs content)
function logFileInfo ( files ) {
const fileInfo = Array . isArray ( files ) ? files : [ files ];
ld . log (
"File info:" ,
fileInfo . map (( f ) => ({
fileName: f . fileName ,
mimeType: f . mimeType ,
size: f . size ,
hasBase64: !! f . base64 ,
hasText: !! f . text , // Only exists for outputs
}))
);
}