Upload & attach file
Attaching files to form fields via Tallyfy’s API is a two-step process:
- Upload the file - send the file to Tallyfy’s upload endpoint and get back an asset object.
- Attach to the field - use that asset object to update the task or template, linking the file to the right form field.
Step 1 - Upload the file
Section titled “Step 1 - Upload the file”Endpoint
Section titled “Endpoint”POST /organizations/{org_id}/file
Both /file and /assets route to the same handler, but /file is the standard endpoint for uploads.
Request type
Section titled “Request type”multipart/form-data
Headers
Section titled “Headers”Authorization: Bearer {your_access_token}Accept: application/jsonX-Tallyfy-Client: APIClient
Don’t set Content-Type manually - your HTTP client sets it automatically for multipart requests.
Form data fields
Section titled “Form data fields”| Field | Required | Description | Example |
|---|---|---|---|
name | Yes | The file binary data (max 100MB) | (file input) |
subject_id | Yes | ID of the parent object - run_id for tasks, checklist_id for kick-off | run_abc123 |
subject_type | Yes | Run for task fields, Checklist for kick-off fields | Run |
uploaded_from | Yes | The form field’s Capture ID for tasks, or ko_field for kick-off fields | capture_id_abc123 |
source | No | How the file is provided - local or url | local |
step_id | No | Step ID within the template (only for task uploads) | step_xyz789 |
checklist_id | No | Template ID the process was launched from (only for task uploads) | template_efg456 |
system | No | External storage system if applicable | Dropbox, Google Drive, etc. |
Allowed file types
Section titled “Allowed file types”The API accepts these extensions: xlsx, xls, pptx, docx, ppt, doc, rtf, pdf, txt, mpga, mov, qt, mp4, webm, jpg, jpeg, gif, png, ai, psd, zip, xml, xps, dwg, csv, tif, bmp.
Code samples for upload
Section titled “Code samples for upload”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 checklistIdForKO = 'TEMPLATE_ID_WITH_KICKOFF';
const fileInput = document.getElementById('yourFileInputId');if (!fileInput?.files?.length) { throw new Error('No file selected.');}const file = fileInput.files[0];
const formData = new FormData();formData.append('name', file, file.name);formData.append('source', 'local');
// 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);
// For kick-off field:// formData.append('uploaded_from', 'ko_field');// formData.append('subject_type', 'Checklist');// formData.append('subject_id', checklistIdForKO);
const response = await fetch(apiUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/json', 'X-Tallyfy-Client': 'APIClient' }, body: formData});
if (!response.ok) { const errData = await response.json().catch(() => response.text()); console.error('Upload failed:', errData); throw new Error(`HTTP error! status: ${response.status}`);}
const result = await response.json();console.log('Uploaded file asset:', JSON.stringify(result, null, 2));// Use result.data for Step 2import requestsimport jsonimport os
access_token = os.environ.get('TALLYFY_ACCESS_TOKEN', 'YOUR_PERSONAL_ACCESS_TOKEN')org_id = os.environ.get('TALLYFY_ORG_ID', 'YOUR_ORGANIZATION_ID')api_url = f'https://go.tallyfy.com/api/organizations/{org_id}/file'
# --- For task field ---form_field_id = 'CAPTURE_ID_OF_FILE_FIELD'run_id = 'PROCESS_RUN_ID'step_id = 'STEP_ID_CONTAINING_FIELD'checklist_id = 'TEMPLATE_ID_OF_RUN'
# --- OR for kick-off field ---# checklist_id_for_ko = 'TEMPLATE_ID_WITH_KICKOFF'
file_path = '/path/to/your/local/document.pdf'
headers = { 'Authorization': f'Bearer {access_token}', 'Accept': 'application/json', 'X-Tallyfy-Client': 'APIClient'}
# For task field:form_data = { 'uploaded_from': (None, form_field_id), 'subject_type': (None, 'Run'), 'subject_id': (None, run_id), 'step_id': (None, step_id), 'checklist_id': (None, checklist_id), 'source': (None, 'local')}
# For kick-off field:# form_data = {# 'uploaded_from': (None, 'ko_field'),# 'subject_type': (None, 'Checklist'),# 'subject_id': (None, checklist_id_for_ko),# 'source': (None, 'local')# }
response = Nonetry: with open(file_path, 'rb') as f: files = {'name': (os.path.basename(file_path), f)} response = requests.post(api_url, headers=headers, data=form_data, files=files)
response.raise_for_status() asset_data = response.json() print('Uploaded file asset:') print(json.dumps(asset_data, indent=4)) # Use asset_data['data'] for Step 2
except FileNotFoundError: print(f'Error: File not found at {file_path}')except requests.exceptions.RequestException as e: print(f'Request failed: {e}') if response is not None: print(f'Status: {response.status_code}, Body: {response.text}')import org.apache.hc.client5.http.classic.methods.HttpPost;import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;import org.apache.hc.client5.http.entity.mime.FileBody;import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;import org.apache.hc.client5.http.impl.classic.HttpClients;import org.apache.hc.core5.http.HttpEntity;import org.apache.hc.core5.http.io.entity.EntityUtils;import org.apache.hc.core5.http.ContentType;
import java.io.File;import java.io.IOException;
public class UploadFileApache { public static void main(String[] args) { String accessToken = System.getenv().getOrDefault("TALLYFY_ACCESS_TOKEN", "YOUR_PERSONAL_ACCESS_TOKEN"); String orgId = System.getenv().getOrDefault("TALLYFY_ORG_ID", "YOUR_ORGANIZATION_ID"); String apiUrl = "https://go.tallyfy.com/api/organizations/" + orgId + "/file"; File fileToUpload = new File("/path/to/your/document.pdf");
String formFieldId = "CAPTURE_ID_OF_FILE_FIELD"; String runId = "PROCESS_RUN_ID"; String stepId = "STEP_ID_CONTAINING_FIELD"; String checklistId = "TEMPLATE_ID_OF_RUN";
if (!fileToUpload.exists()) { System.err.println("File not found: " + fileToUpload.getPath()); return; }
try (CloseableHttpClient client = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(apiUrl); httpPost.setHeader("Authorization", "Bearer " + accessToken); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("X-Tallyfy-Client", "APIClient");
MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addPart("name", new FileBody(fileToUpload)); builder.addTextBody("source", "local", ContentType.TEXT_PLAIN); builder.addTextBody("uploaded_from", formFieldId, ContentType.TEXT_PLAIN); builder.addTextBody("subject_type", "Run", ContentType.TEXT_PLAIN); builder.addTextBody("subject_id", runId, ContentType.TEXT_PLAIN); builder.addTextBody("step_id", stepId, ContentType.TEXT_PLAIN); builder.addTextBody("checklist_id", checklistId, ContentType.TEXT_PLAIN);
httpPost.setEntity(builder.build());
client.execute(httpPost, response -> { int status = response.getCode(); HttpEntity entity = response.getEntity(); String body = entity != null ? EntityUtils.toString(entity) : null; if (status >= 200 && status < 300) { System.out.println("Upload successful:"); System.out.println(body); // Parse body JSON to get asset object for Step 2 } else { System.err.println("Upload failed. Status: " + status); System.err.println("Response: " + body); } return body; });
} catch (IOException e) { System.err.println("Request failed: " + e.getMessage()); e.printStackTrace(); } }}package main
import ( "bytes" "fmt" "io" "mime/multipart" "net/http" "os" "path/filepath" "time")
func main() { accessToken := os.Getenv("TALLYFY_ACCESS_TOKEN") if accessToken == "" { accessToken = "YOUR_PERSONAL_ACCESS_TOKEN" } orgId := os.Getenv("TALLYFY_ORG_ID") if orgId == "" { orgId = "YOUR_ORGANIZATION_ID" } apiUrl := fmt.Sprintf("https://go.tallyfy.com/api/organizations/%s/file", orgId) filePath := "/path/to/your/image.png"
formFieldId := "CAPTURE_ID_OF_FILE_FIELD" runId := "PROCESS_RUN_ID" stepId := "STEP_ID_CONTAINING_FIELD" checklistId := "TEMPLATE_ID_OF_RUN"
file, err := os.Open(filePath) if err != nil { fmt.Printf("Error opening file: %v\n", err) return } defer file.Close()
body := &bytes.Buffer{} writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("name", filepath.Base(filePath)) if err != nil { fmt.Printf("Error creating form file: %v\n", err) return } _, err = io.Copy(part, file) if err != nil { fmt.Printf("Error copying file data: %v\n", err) return }
_ = writer.WriteField("uploaded_from", formFieldId) _ = writer.WriteField("subject_type", "Run") _ = writer.WriteField("subject_id", runId) _ = writer.WriteField("step_id", stepId) _ = writer.WriteField("checklist_id", checklistId) _ = writer.WriteField("source", "local")
err = writer.Close() if err != nil { fmt.Printf("Error closing multipart writer: %v\n", err) return }
client := &http.Client{Timeout: 60 * time.Second} req, err := http.NewRequest("POST", apiUrl, body) if err != nil { fmt.Printf("Error creating request: %v\n", err) return }
req.Header.Set("Authorization", "Bearer "+accessToken) req.Header.Set("Accept", "application/json") req.Header.Set("X-Tallyfy-Client", "APIClient") req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := client.Do(req) if err != nil { fmt.Printf("Error executing request: %v\n", err) return } defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Error reading response: %v\n", err) return }
if resp.StatusCode != http.StatusOK { fmt.Printf("Upload failed. Status: %d\nBody: %s\n", resp.StatusCode, string(respBody)) return }
fmt.Println("Upload successful:") fmt.Println(string(respBody)) // Parse JSON to extract asset object for Step 2}using System;using System.IO;using System.Net.Http;using System.Net.Http.Headers;using System.Threading.Tasks;
public class TallyfyFileUpload{ private static readonly HttpClient client = new HttpClient();
public static async Task<string> UploadFileAsync(string filePath) { var accessToken = Environment.GetEnvironmentVariable("TALLYFY_ACCESS_TOKEN") ?? "YOUR_PERSONAL_ACCESS_TOKEN"; var orgId = Environment.GetEnvironmentVariable("TALLYFY_ORG_ID") ?? "YOUR_ORGANIZATION_ID"; var apiUrl = $"https://go.tallyfy.com/api/organizations/{orgId}/file";
string formFieldId = "CAPTURE_ID_OF_FILE_FIELD"; string runId = "PROCESS_RUN_ID"; string stepId = "STEP_ID_CONTAINING_FIELD"; string checklistId = "TEMPLATE_ID_OF_RUN";
if (!File.Exists(filePath)) { Console.WriteLine($"Error: File not found at {filePath}"); return null; }
using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Add("X-Tallyfy-Client", "APIClient");
using var form = new MultipartFormDataContent(); using var fileStream = File.OpenRead(filePath); using var streamContent = new StreamContent(fileStream); form.Add(streamContent, "name", Path.GetFileName(filePath)); form.Add(new StringContent("local"), "source"); form.Add(new StringContent(formFieldId), "uploaded_from"); form.Add(new StringContent("Run"), "subject_type"); form.Add(new StringContent(runId), "subject_id"); form.Add(new StringContent(stepId), "step_id"); form.Add(new StringContent(checklistId), "checklist_id");
request.Content = form;
try { HttpResponseMessage response = await client.SendAsync(request); string responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode) { Console.WriteLine("Upload successful:"); Console.WriteLine(responseBody); return responseBody; } else { Console.WriteLine($"Upload failed. Status: {response.StatusCode}"); Console.WriteLine($"Response: {responseBody}"); return null; } } catch (HttpRequestException e) { Console.WriteLine($"Request error: {e.Message}"); return null; } }}Upload response
Section titled “Upload response”A successful upload returns 200 OK with the asset object wrapped in data. You’ll need this object for Step 2.
{ "data": { "id": "asset_id_abc123xyz", "filename": "document.pdf", "version": 1, "uploaded_from": "capture_id_abc123", "uploaded_at": "2024-01-15T10:00:00Z", "step_id": "step_id_xyz789", "source": "local", "system": null, "uploaded_to_s3": true, "subject": { "id": "run_id_abc", "type": "Run" } }}Step 2 - Attach the uploaded file to a field
Section titled “Step 2 - Attach the uploaded file to a field”Use the asset object from Step 1 to update the task or template, linking the file to the form field.
Endpoint
Section titled “Endpoint”- Task field:
PUT /organizations/{org_id}/runs/{run_id}/tasks/{task_id} - Kick-off field:
PUT /organizations/{org_id}/checklists/{checklist_id}
Request type
Section titled “Request type”application/json
Headers
Section titled “Headers”Authorization: Bearer {your_access_token}Accept: application/jsonX-Tallyfy-Client: APIClientContent-Type: application/json
Body for task fields
Section titled “Body for task fields”The taskdata object uses the form field’s Capture ID as the key. The value is an array containing the asset object from Step 1.
{ "taskdata": { "CAPTURE_ID_OF_FILE_FIELD": [ { "id": "asset_id_abc123xyz", "filename": "document.pdf", "version": 1, "uploaded_from": "capture_id_abc123", "uploaded_at": "2024-01-15T10:00:00Z", "step_id": "step_id_xyz789", "source": "local", "uploaded_to_s3": true, "subject": { "id": "run_id_abc", "type": "Run" } } ] }}Body for kick-off fields
Section titled “Body for kick-off fields”Update the template’s prerun array. Set the value for your file field to an array containing the asset object from Step 1.
{ "prerun": [ { "id": "PRERUN_FIELD_ID_FOR_FILE", "value": [ { "id": "asset_id_abc123xyz", "filename": "document.pdf", "version": 1, "uploaded_from": "ko_field", "uploaded_at": "2024-01-15T10:00:00Z", "source": "local", "uploaded_to_s3": true, "subject": { "id": "checklist_id_abc", "type": "Checklist" } } ] } ]}Code samples for attaching
Section titled “Code samples for attaching”These examples assume you have the assetObject from Step 1 and the required IDs.
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] } };
const response = await fetch(apiUrl, { method: 'PUT', headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/json', 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
const responseData = await response.json();
if (!response.ok) { console.error('Failed to attach file:', responseData); throw new Error(`HTTP error! status: ${response.status}`); }
console.log('File attached successfully:', JSON.stringify(responseData, null, 2));}import requestsimport json
def attach_file_to_task(org_id, run_id, task_id, form_field_id, asset_object, access_token): api_url = f'https://go.tallyfy.com/api/organizations/{org_id}/runs/{run_id}/tasks/{task_id}'
payload = { 'taskdata': { form_field_id: [asset_object] } }
headers = { 'Authorization': f'Bearer {access_token}', 'Accept': 'application/json', 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }
response = requests.put(api_url, headers=headers, json=payload) response.raise_for_status()
updated_task = response.json() print('File attached successfully:') print(json.dumps(updated_task, indent=4)) return updated_taskimport java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.io.IOException;
public class AttachFile {
public static void attachFileToTask(String orgId, String runId, String taskId, String formFieldId, String assetJsonString, String accessToken) { String apiUrl = String.format( "https://go.tallyfy.com/api/organizations/%s/runs/%s/tasks/%s", orgId, runId, taskId);
String jsonPayload = String.format( "{\"taskdata\": {\"%s\": [%s]}}", formFieldId, assetJsonString);
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(apiUrl)) .header("Authorization", "Bearer " + accessToken) .header("Accept", "application/json") .header("X-Tallyfy-Client", "APIClient") .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(jsonPayload)) .build();
try { HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { System.out.println("File attached to task " + taskId + ":"); System.out.println(response.body()); } else { System.err.println("Failed. Status: " + response.statusCode()); System.err.println("Response: " + response.body()); } } catch (IOException | InterruptedException e) { System.err.println("Request failed: " + e.getMessage()); Thread.currentThread().interrupt(); } }}package main
import ( "bytes" "encoding/json" "fmt" "io" "net/http" "time")
func attachFileToTask(orgId, runId, taskId, formFieldId string, assetObject map[string]interface{}, accessToken string) {
apiUrl := fmt.Sprintf( "https://go.tallyfy.com/api/organizations/%s/runs/%s/tasks/%s", orgId, runId, taskId)
payload := map[string]interface{}{ "taskdata": map[string]interface{}{ formFieldId: []interface{}{assetObject}, }, }
payloadBytes, err := json.Marshal(payload) if err != nil { fmt.Printf("Error marshalling payload: %v\n", err) return }
client := &http.Client{Timeout: 15 * time.Second} req, err := http.NewRequest(http.MethodPut, apiUrl, bytes.NewBuffer(payloadBytes)) if err != nil { fmt.Printf("Error creating request: %v\n", err) return }
req.Header.Set("Authorization", "Bearer "+accessToken) req.Header.Set("Accept", "application/json") req.Header.Set("X-Tallyfy-Client", "APIClient") req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req) if err != nil { fmt.Printf("Error executing request: %v\n", err) return } defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Error reading response: %v\n", err) return }
if resp.StatusCode != http.StatusOK { fmt.Printf("Failed. Status: %d\nBody: %s\n", resp.StatusCode, string(respBody)) return }
fmt.Println("File attached successfully:") var prettyJSON bytes.Buffer if err := json.Indent(&prettyJSON, respBody, "", " "); err == nil { fmt.Println(prettyJSON.String()) } else { fmt.Println(string(respBody)) }}using System;using System.Net.Http;using System.Net.Http.Headers;using System.Text;using System.Text.Json.Nodes;using System.Threading.Tasks;
public class TallyfyFileAttacher{ private static readonly HttpClient client = new HttpClient();
public static async Task AttachFileToTaskAsync(string assetJsonString, string orgId, string runId, string taskId, string formFieldId, string accessToken) { var apiUrl = $"https://go.tallyfy.com/api/organizations/{orgId}/runs/{runId}/tasks/{taskId}";
var assetNode = JsonNode.Parse(assetJsonString); var payload = new JsonObject { ["taskdata"] = new JsonObject { [formFieldId] = new JsonArray { JsonNode.Parse(assetNode.ToJsonString()) } } };
using var request = new HttpRequestMessage(HttpMethod.Put, apiUrl); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Add("X-Tallyfy-Client", "APIClient"); request.Content = new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(request); string responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode) { Console.WriteLine($"File attached to task {taskId}:"); Console.WriteLine(responseBody); } else { Console.WriteLine($"Failed. Status: {response.StatusCode}"); Console.WriteLine($"Response: {responseBody}"); } }}Attach response
Section titled “Attach response”A successful PUT returns 200 OK with the updated task or template object. The file attachment appears under the field’s Capture ID in taskdata.
{ "data": { "taskdata": { "CAPTURE_ID_OF_FILE_FIELD": [ { "id": "asset_id_abc123xyz", "filename": "document.pdf", "version": 1, "uploaded_from": "capture_id_abc123", "uploaded_at": "2024-01-15T10:00:00Z", "step_id": "step_id_xyz789", "source": "local", "uploaded_to_s3": true, "subject": { "id": "run_id_abc", "type": "Run" } } ] } }}Related articles
Section titled “Related articles”Postman > Task operations and automation
Was this helpful?
- 2026 Tallyfy, Inc.
- Privacy Policy
- Terms of Use
- Report Issue
- Trademarks