Skip to content

Upload & attach file

Attaching files (like images or documents) to form fields via the API usually involves two main steps for files stored locally on your system:

  1. Upload the file: Send the file content to Tallyfy’s file endpoint to get an asset reference.
  2. Update the task/process: Use the asset reference obtained in step 1 to update the corresponding task or process, linking the file to the specific form field.

Alternatively, for files already hosted publicly online, you might be able to link them directly in a single step (see Method 2 in the older article content, though this might be less common and subject to change - prioritize the upload method).

Step 1: Upload the file

Endpoint

POST /organizations/{org_id}/file

Request type

multipart/form-data

This request uploads the raw file data. It requires specific form data fields to correctly categorize the upload.

Headers

  • Authorization: Bearer {your_access_token}
  • Accept: application/json
  • X-Tallyfy-Client: APIClient
  • (Content-Type header will be set automatically by your HTTP client for multipart/form-data)

Form data fields (required)

FieldDescriptionExample Value
nameThe actual file binary data.(Select file in your client)
uploaded_fromContext of upload. For Tasks, use the Form Field ID (Capture ID). For Kick-off, use ko_field.capture_id_abc123 or ko_field
subject_typeType of object the file relates to.Run (for Tasks) or Checklist (for Kick-off)
subject_idID of the object type.{run_id} (for Tasks) or {checklist_id} (for Kick-off)
sourceHow the file is provided.local
step_idRequired only for Tasks. The ID of the Step within the template that the task belongs to.step_id_xyz789
checklist_idRequired only for Tasks. The ID of the template (Checklist) that the process run was launched from.template_id_efg456

Code samples for Step 1: Upload

(Note: Handling multipart/form-data varies significantly between languages and libraries. These are conceptual examples.)

const accessToken = 'YOUR_PERSONAL_ACCESS_TOKEN';
const orgId = 'YOUR_ORGANIZATION_ID';
const apiUrl = `https://go.tallyfy.com/api/organizations/${orgId}/file`;
// --- For Task Field ---
const formFieldId = 'CAPTURE_ID_OF_FILE_FIELD';
const runId = 'PROCESS_RUN_ID';
const stepId = 'STEP_ID_CONTAINING_FIELD';
const checklistId = 'TEMPLATE_ID_OF_RUN';
// --- OR For Kick-off Field ---
// const prerunFieldId = 'ko_field'; // Use 'ko_field' for uploaded_from
// const checklistIdForKO = 'TEMPLATE_ID_WITH_KICKOFF';
// Assume 'fileInput' is an HTML <input type="file"> element
const fileInput = document.getElementById('yourFileInputId');
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
console.error("No file selected or file input not found!");
// Stop execution or handle error appropriately
throw new Error("File input error.");
}
const file = fileInput.files[0];
const formData = new FormData();
formData.append('name', file, file.name);
formData.append('source', 'local');
// --- Populate based on target (Task or Kick-off) ---
// Example for Task Field:
formData.append('uploaded_from', formFieldId);
formData.append('subject_type', 'Run');
formData.append('subject_id', runId);
formData.append('step_id', stepId);
formData.append('checklist_id', checklistId);
// Example for Kick-off Field:
// formData.append('uploaded_from', 'ko_field');
// formData.append('subject_type', 'Checklist');
// formData.append('subject_id', checklistIdForKO);
// --- End Target Specific ---
const headers = new Headers();
headers.append('Authorization', `Bearer ${accessToken}`);
headers.append('Accept', 'application/json');
headers.append('X-Tallyfy-Client', 'APIClient');
// Content-Type is set automatically by fetch for FormData
fetch(apiUrl, {
method: 'POST',
headers: headers,
body: formData
})
.then(response => {
if (!response.ok) {
// Try to parse error JSON, fallback to text
return response.json()
.catch(() => response.text()) // If JSON parsing fails
.then(errData => {
console.error("Upload failed:", errData);
throw new Error(`HTTP error! status: ${response.status}`);
});
}
return response.json();
})
.then(data => {
console.log('Successfully uploaded file. Asset data:');
console.log(JSON.stringify(data, null, 2));
// NOW PROCEED TO STEP 2 using data.data[0] (or similar based on actual response)
// Example: const assetObject = data.data[0]; attachFileToTask(assetObject);
})
.catch(error => {
console.error('Error uploading file:', error.message);
});

Response examples for Step 1: Upload

A successful upload returns 200 OK and a JSON response containing an array usually with one element: the asset object representing the uploaded file. You need this object for Step 2.

{
"data": [
{
"id": "asset_id_abc123xyz", // The Asset ID
"filename": "document.pdf",
"version": 1,
"step_id": "step_id_xyz789", // If uploaded for a task
"uploaded_from": "capture_id_abc123", // Form Field ID or ko_field
"subject": {
"id": "run_id_or_checklist_id",
"type": "Run" // or "Checklist"
},
"url": "/internal/url/not/usually/needed/directly",
"uploaded_at": "2024-05-21T10:00:00Z"
// Potentially other fields like uploaded_to_s3
}
]
}

Extract the entire object within the data array (e.g., response.data[0] in JavaScript) for the next step.

Step 2: Attach uploaded file to field

Now, use the asset object obtained from Step 1 to update the specific task or process run, linking the file to the form field.

Endpoint

  • Process Task: PUT /organizations/{org_id}/runs/{run_id}/tasks/{task_id}
  • Kick-off Form: PUT /organizations/{org_id}/checklists/{checklist_id} (Modify the prerun field in the template update payload)

Request type

application/json

Headers

  • Authorization: Bearer {your_access_token}
  • Accept: application/json
  • X-Tallyfy-Client: APIClient
  • Content-Type: application/json

Body JSON for task fields

Update the task using its endpoint. The body should include a taskdata object targeting the file field ID. The value should be an array containing the asset object from Step 1.

{
"taskdata": {
"CAPTURE_ID_OF_FILE_FIELD": [
{
"id": "asset_id_abc123xyz",
"filename": "document.pdf",
"version": 1,
"step_id": "step_id_xyz789",
"uploaded_from": "capture_id_abc123",
"subject": {
"id": "run_id_or_checklist_id",
"type": "Run"
},
"url": "...",
"uploaded_at": "...",
"uploaded_to_s3": true
}
]
}
// You can include other task updates here too (e.g., summary, deadline)
}

Body JSON for kick-off fields

Update the template using its endpoint. The body needs to include the prerun array, modifying the entry for your file field. The value for the file field should be an array containing the asset object from Step 1.

{
"prerun": [
// ... other prerun fields (MUST include their existing IDs and values or they might be removed) ...
{
"id": "PRERUN_FIELD_ID_FOR_FILE", // ID of the kick-off field
// It's safest to fetch the existing prerun fields first and modify only the target one.
// Include other necessary properties for this field (like label, field_type, required etc.).
"value": [ // The value is an array containing the asset object
// Paste the entire asset object from Step 1 response's data[0] here
{
"id": "asset_id_abc123xyz",
"filename": "document.pdf",
// ... all other fields from Step 1 data[0] ...
}
]
}
// ... other prerun fields ...
]
// Include other template updates if needed (e.g., title)
}

Code samples for Step 2: Attach file to task

(These examples assume you have the assetObject from the Step 1 response and the necessary IDs: orgId, runId, taskId, formFieldId)

async function attachFileToTask(assetObject, orgId, runId, taskId, formFieldId, accessToken) {
const apiUrl = `https://go.tallyfy.com/api/organizations/${orgId}/runs/${runId}/tasks/${taskId}`;
const payload = {
taskdata: {
[formFieldId]: [assetObject] // Key is the Form Field ID, value is array with asset object
}
// Add other task updates if needed
};
const headers = new Headers();
headers.append('Authorization', `Bearer ${accessToken}`);
headers.append('Accept', 'application/json');
headers.append('X-Tallyfy-Client', 'APIClient');
headers.append('Content-Type', 'application/json');
try {
const response = await fetch(apiUrl, {
method: 'PUT',
headers: headers,
body: JSON.stringify(payload)
});
const responseData = await response.json(); // Try parsing JSON regardless of status for error details
if (!response.ok) {
console.error("Failed to attach file to task:", responseData);
throw new Error(`HTTP error! status: ${response.status}`);
}
console.log("Successfully attached file to task:");
console.log(JSON.stringify(responseData, null, 2));
} catch (error) {
console.error('Error attaching file:', error.message);
}
}
// Example Usage (after getting assetObject from Step 1):
// const assetFromStep1 = { id: 'asset_id...', filename: '...', ... };
// attachFileToTask(assetFromStep1, 'orgId', 'runId', 'taskId', 'formFieldId', 'token');

Response examples for Step 2: Attach

A successful PUT request returns 200 OK and the updated Task or Checklist object, reflecting the file attachment in the taskdata or prerun.value respectively.

{
// ... other task properties ...
"taskdata": {
"CAPTURE_ID_OF_FILE_FIELD": [
{
"id": "asset_id_abc123xyz",
"filename": "document.pdf",
"version": 1,
"step_id": "step_id_xyz789",
"uploaded_from": "capture_id_abc123",
"subject": {
"id": "run_id_or_checklist_id",
"type": "Run"
},
"url": "...",
"uploaded_at": "...",
"uploaded_to_s3": true
}
]
}
// ... other task properties ...
}

Code Samples > Managing files

The API enables file management functionalities including uploading downloading getting metadata and removing files associated with tasks or kick-off forms.

Files > Delete file

A DELETE endpoint that removes uploaded files from tasks or kick-off forms by making authorized requests to either /organizations/[org_id]/file/[asset_id] or /organizations/[org]/assets/[assetID] endpoints and returns a 200 OK status code upon successful deletion.

Files > Download file

An API endpoint that downloads file content using various programming languages including JavaScript Python Java and Go by sending a GET request with proper authentication headers to retrieve the raw file data.

Tasks > Update task

Updates existing tasks by modifying properties like title description deadline assignees and form field values through a PUT request to the Tallyfy API endpoint.