---
updatedAt: 2025-09-25T21:10:45.000Z
agentTools:
  projectIndex: https://developers.toriihq.com/llms.txt
---

# Download all Files

```node Node
// downloader.js

const axios = require('axios');
const fs = require('fs');
const path = require('path');

// Replace with your actual API key
const API_KEY = 'YOUR_API_KEY';

// Base URL for Torii API
const BASE_URL = 'https://api.toriihq.com/v1.0';

// Counters for downloads
let contractsDownloaded = 0;
const appFilesDownloaded = {};

// Function to get contracts with documents and idApp
async function getContractsWithDocuments() {
    try {
        const response = await axios.get(`${BASE_URL}/contracts?fields=id,idApp,documents`, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            }
        });
        return response.data.contracts.filter(contract => contract.documents && contract.documents.length > 0);
    } catch (error) {
        console.error('Error fetching contracts:', error.response ? error.response.data : error.message);
        return [];
    }
}

// Function to get apps with documents and idApp
async function getAppsWithDocuments(fileFields) {
    try {
        const fields = fileFields.map(field => field.systemKey)
        let url = `${BASE_URL}/apps?fields=id,name`
        if (fileFields.length > 0) {
            url += "," + fields.join(",")
        }
        const response = await axios.get(url, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            }
        });
        const apps = response.data.apps;

        // Filter only apps that have attachments
        let appsWithFiles = apps.filter(app =>
            fields.some(key => app.hasOwnProperty(key))
        )
        return appsWithFiles;
    } catch (error) {
        console.error('Error fetching contracts:', error.response ? error.response.data : error.message);
        return [];
    }
}

// Function to get the app name by idApp
async function getAppName(idApp) {
    try {
        const response = await axios.get(`${BASE_URL}/apps/${idApp}?fields=id,name`, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            }
        });
        return response.data.app.name; // Corrected to access the name inside the app object
    } catch (error) {
        if (error.response && error.response.status === 404) {
            console.error(`App not found for idApp ${idApp}. Skipping...`);
            return null; // Return null if the app is not found
        } else {
            console.error(`Error fetching app name for idApp ${idApp}:`, error.response ? error.response.data : error.message);
            return `app_${idApp}`; // Fallback name in case of other errors
        }
    }
}

// Function to get all app fields of type "fileUpload"
async function getFileUploadFields() {
    try {
        const response = await axios.get(`${BASE_URL}/apps/fields`, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            }
        });
        return response.data.fields
            .filter(field => field.type === 'fileUpload')
            .map(field => ({ systemKey: field.systemKey, name: field.name }));
    } catch (error) {
        console.error('Error fetching app fields:', error.response ? error.response.data : error.message);
        return [];
    }
}

// Function to get files attached to an app by idApp and specified fields
async function getAppFiles(idApp, field) {
    try {
        const response = await axios.get(`${BASE_URL}/apps/${idApp}?fields=${field.systemKey}`, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            }
        });
        return response.data.app[field.systemKey] || [];
    } catch (error) {
        console.error(`Error fetching files for app ${idApp}:`, error.response ? error.response.data : error.message);
        return [];
    }
}

// Function to download a document using idUpload
async function downloadDocument(document, outputPath, fileType) {
    try {
        const response = await axios.get(`${BASE_URL}/files/${document.idUpload}/download`, {
            headers: {
                'Authorization': `Bearer ${API_KEY}`
            },
            responseType: 'stream' // Ensure the response is a stream so we can pipe it to a file
        });

        // Ensure the directory exists
        fs.mkdirSync(path.dirname(outputPath), { recursive: true });

        // Stream the file to disk
        const writer = fs.createWriteStream(outputPath);
        response.data.pipe(writer);

        writer.on('finish', () => {
            console.log(`Downloading (${fileType}): ${document.name}`);
        });

        writer.on('error', (error) => {
            console.error('Error writing file:', error);
        });
    } catch (error) {
        console.error(`Error downloading document ${document.name}:`, error.response ? error.response.data : error.message);
    }
}

// Main function to download all documents from contracts and app attachments
async function downloadAllDocuments() {
    const contracts = await getContractsWithDocuments();
    const fileUploadFields = await getFileUploadFields();
    const apps = await getAppsWithDocuments(fileUploadFields);

    console.log(`Found ${contracts.length} contracts with documents.`);
    console.log(`Found ${apps.length} apps with documents.`);
    console.log(`Found ${fileUploadFields.length} file upload fields.`);

    for (const contract of contracts) {
        const appName = await getAppName(contract.idApp);

        if (!appName) {
            // Skip this contract if the app name could not be retrieved
            continue;
        }

        const appFolderPath = path.join(__dirname, 'downloads', appName, 'contracts');

        for (const document of contract.documents) {
            const documentPath = path.join(appFolderPath, document.name);
            await downloadDocument(document, documentPath, 'Contract');
            contractsDownloaded++;
        }
    }

    // Download app's attachments and save them in folders named after the field names
    for (const app of apps) {
        for (const field of fileUploadFields) {
            const attachments = await getAppFiles(app.id, field);
            const fieldFolderPath = path.join(__dirname, 'downloads', app.name, field.name);

            if (!appFilesDownloaded[field.name]) {
                appFilesDownloaded[field.name] = 0;
            }

            for (const attachment of attachments) {
                const attachmentPath = path.join(fieldFolderPath, attachment.name);
                await downloadDocument(attachment, attachmentPath, field.name);
                appFilesDownloaded[field.name]++;
            }
        }
    }


    // Log the results
    console.log(`\nDownload Summary:`);
    console.log(`Contracts downloaded: ${contractsDownloaded}`);
    for (const [fieldName, count] of Object.entries(appFilesDownloaded)) {
        console.log(`${fieldName} files downloaded: ${count}`);
    }
}

// Run the script
downloadAllDocuments();
```

```json Response Example
{"success":true}
```

# Define constants

<!-- node@3-5 -->

Declare block-scoped local variables for axios, fs, and path.

# Update script with your API key (TO DO)

<!-- node@8 -->

Update YOUR_API_KEY, the text in single quotes with the API key you create from your Torii account.  Note that you will need the single quotes around your API key.

# Defines Base URL

<!-- node@11 -->

Sets a constant for the base URL for the Torii API.

# Function to get contracts and documents

<!-- node@17-30 -->

This function makes a call to the Torii API to retrieve contracts that have documents attached to them.  The Torii endpoint called by this function is - https://developers.toriihq.com/reference/getcontracts

# Function to get apps with documents

<!-- node@32-56 -->

This function makes a request to the Torii API to get apps with documents attached to them.  The endpoint used to make this request can be found in the API explorer - https://developers.toriihq.com/reference/getapps.

# Function to get the app name based on the ID

<!-- node@58-76 -->

This function makes a request to the Torii API to derive application names using the unique IDs of the apps.  The Torii API endpoint used for this is - https://developers.toriihq.com/reference/getappsidapp.

# Function to get the fileUpload fields for apps

<!-- node@78-93 -->

This function makes requests to the Torii API to get file upload fields for apps that have files or documents attached.  It uses the /apps/fields path to retrieve all fields for apps as documented in the API explorer for the request - https://developers.toriihq.com/reference/getapps

# Function to get files attached to an app

<!-- node@95-108 -->

This function gets the files attached to an app and their associated fields.

# Function to download the documents or files that are found

<!-- node@110-137 -->

This function downloads documents using this endpoint from the Torii API - https://developers.toriihq.com/reference/getfilesiddownload

# Main function of the script

<!-- node@139-191 -->

This is the main function of the scrypt that loops through contracts and apps with documents and invokes the functions defined previously to build the metadata and download the files.