Workato > Complete Tallyfy tasks from Workato
Task operations and automation
To work with tasks in Postman, use the tasks endpoints to list, complete, and update task data including form fields and file attachments. Tasks are the individual work items within running processes that users complete.
In Tallyfy’s API:
- Tasks = Individual work items in a running process
- Captures = Form field data within tasks
- Assignments = Who’s responsible for completing the task
GET {{TALLYFY_BASE_URL}}/organizations/{{TALLYFY_ORG_ID}}/me/tasks
Headers:Authorization: Bearer {{TALLYFY_ACCESS_TOKEN}}X-Tallyfy-Client: APIClient
Query parameters:- status: active, completed- limit: 100- offset: 0
GET {{TALLYFY_BASE_URL}}/runs/{{PROCESS_ID}}/tasks
// Advanced filtering in Tests tabconst tasks = pm.response.json().data;
// Overdue tasksconst overdueTasks = tasks.filter(t => t.deadline && new Date(t.deadline) < new Date() && t.status === 'active');
// Tasks by specific assigneeconst userTasks = tasks.filter(t => t.assignees.some(a => a.email === 'john@company.com'));
// High priority tasks (based on process name or custom logic)const urgentTasks = tasks.filter(t => t.run_name.includes('URGENT') || t.run_name.includes('Priority'));
console.log(`Found ${overdueTasks.length} overdue tasks`);
PUT {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}/complete
Headers:Authorization: Bearer {{TALLYFY_ACCESS_TOKEN}}X-Tallyfy-Client: APIClient
Most tasks have form fields that need values:
PUT {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}/complete
Body:{ "captures": { "field_abc123": "Approved", "field_def456": 42.50, "field_ghi789": "Task completed successfully with no issues", "field_jkl012": true }}
Complete multiple tasks efficiently:
const taskIds = ["task_123", "task_456", "task_789"];const results = [];
// Function to complete a single taskfunction completeTask(taskId, captures = {}) { return new Promise((resolve, reject) => { pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/tasks/${taskId}/complete`, method: 'PUT', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ captures }) } }, (err, res) => { if (err) { reject(err); } else { resolve({ taskId, status: res.code }); } }); });}
// Complete tasks with delay to avoid rate limitsasync function completeTasks() { for (let i = 0; i < taskIds.length; i++) { try { const result = await completeTask(taskIds[i], { field_status: "Completed via API", field_date: new Date().toISOString() }); results.push(result); console.log(`Completed task ${i + 1} of ${taskIds.length}`);
// Add delay between requests if (i < taskIds.length - 1) { await new Promise(resolve => setTimeout(resolve, 200)); } } catch (error) { console.error(`Failed to complete task ${taskIds[i]}:`, error); } }
console.log('Bulk completion results:', results);}
completeTasks();
File uploads require special handling in Postman. Here’s the expert approach:
-
Set up the request
POST {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}/filesHeaders:Authorization: Bearer {{TALLYFY_ACCESS_TOKEN}}X-Tallyfy-Client: APIClient// DO NOT set Content-Type - let Postman handle it -
Configure body as form-data
- Select Body → form-data
- Add key:
file
(type: File) - Add key:
field_id
(type: Text, value: field_abc123)
-
Select file
- Click Select Files for the file field
- Choose your file (max 5MB for team uploads)
- Send request
Critical insights from Postman experts:
- Never set Content-Type manually: Postman automatically sets
multipart/form-data
with proper boundary fields. Manual setting causes “Missing start boundary” errors - Boundary field importance: The boundary separates form parts - Postman generates cryptographically secure boundaries automatically
- File size considerations: Individual files can’t exceed 5MB for shared team collections
- Variable file paths: Use environment variables for dynamic file selection:
// In pre-request scriptconst filePath = pm.environment.get("UPLOAD_FILE_PATH");pm.request.body.formdata.add({key: "file",src: filePath,type: "file"});
Advanced file upload patterns:
// Dynamic file selection based on task typeconst taskType = pm.environment.get("CURRENT_TASK_TYPE");const fileMapping = { "approval": "approval_document.pdf", "review": "review_checklist.xlsx", "signature": "contract_template.docx"};
const fileName = fileMapping[taskType] || "default_file.txt";pm.environment.set("UPLOAD_FILENAME", fileName);
Common mistake: Using raw JSON body instead of form-data. Files must use multipart/form-data with proper boundary handling.
GET {{TALLYFY_BASE_URL}}/files/{{FILE_ID}}/download
Headers:Authorization: Bearer {{TALLYFY_ACCESS_TOKEN}}X-Tallyfy-Client: APIClient
Save response using Postman’s “Save Response” → “Save to a file” option.
PUT {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}
Body:{ "assignees": ["member_123", "member_456"]}
Assign to least busy team member:
// First, get all team members and their task countsasync function assignToLeastBusy(taskId) { // Get all members const membersResponse = await pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/organizations/${pm.environment.get("TALLYFY_ORG_ID")}/members`, method: 'GET', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient' } });
const members = membersResponse.json().data;
// Get task counts for each member const taskCounts = await Promise.all(members.map(async (member) => { const tasksResponse = await pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/organizations/${pm.environment.get("TALLYFY_ORG_ID")}/members/${member.id}/tasks?status=active`, method: 'GET', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient' } });
return { memberId: member.id, name: member.name, taskCount: tasksResponse.json().data.length }; }));
// Find member with least tasks const leastBusy = taskCounts.reduce((prev, current) => prev.taskCount < current.taskCount ? prev : current );
console.log(`Assigning to ${leastBusy.name} (${leastBusy.taskCount} active tasks)`);
// Assign the task return pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/tasks/${taskId}`, method: 'PUT', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ assignees: [leastBusy.memberId] }) } });}
Automatically approve tasks based on conditions:
// Check task data and auto-approve if conditions metconst task = pm.response.json();
if (task.name.includes("Auto-Approval") && task.run_name.includes("Low Risk")) { pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/tasks/${task.id}/complete`, method: 'PUT', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ captures: { field_approval: "Auto-approved", field_notes: "Automatically approved based on low risk criteria", field_timestamp: new Date().toISOString() } }) } }, (err, res) => { if (!err) { console.log("Task auto-approved successfully"); } });}
Find and escalate overdue tasks:
// Get all active tasksconst tasks = pm.response.json().data;const now = new Date();
const overdueTasks = tasks.filter(t => { if (!t.deadline || t.status !== 'active') return false; return new Date(t.deadline) < now;});
// Escalate each overdue taskoverdueTasks.forEach(task => { const hoursOverdue = Math.floor((now - new Date(task.deadline)) / (1000 * 60 * 60));
// Add comment about escalation pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/tasks/${task.id}/comments`, method: 'POST', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ content: `⚠️ ESCALATION: This task is ${hoursOverdue} hours overdue. Manager notified.` }) } });
// Could also reassign to manager or send notifications});
POST {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}/comments
Body:{ "content": "Please review the attached documents before approving."}
GET {{TALLYFY_BASE_URL}}/tasks/{{TASK_ID}}/comments
Complete tasks differently based on previous task data:
// Get process data firstconst process = pm.response.json();
// Find specific task dataconst approvalTask = process.tasks.find(t => t.name.includes("Manager Approval"));const approvalStatus = approvalTask?.captures?.field_approval_status;
// Complete next task based on approvalconst nextTask = process.tasks.find(t => t.name.includes("Next Step") && t.status === 'active');
if (nextTask) { const captures = {};
if (approvalStatus === "Approved") { captures.field_action = "Proceed"; captures.field_notes = "Approved by manager"; } else { captures.field_action = "Revise"; captures.field_notes = "Requires revision per manager feedback"; }
// Complete with appropriate data pm.sendRequest({ url: `${pm.environment.get("TALLYFY_BASE_URL")}/tasks/${nextTask.id}/complete`, method: 'PUT', header: { 'Authorization': `Bearer ${pm.environment.get("TALLYFY_ACCESS_TOKEN")}`, 'X-Tallyfy-Client': 'APIClient', 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ captures }) } });}
Common causes:
- Task already completed
- Not assigned to you
- Required fields missing
- Previous dependencies not complete
- Maximum file size: 25MB typically
- Supported formats: Most common formats
- Use form-data, not JSON
- Include field_id if required
Tallyfy’s form validation follows strict patterns. Here’s what actually works:
Data type matching:
// Common validation patternsconst fieldValidation = { // String fields - any text "field_notes": "Any text value",
// Number fields - must be numeric, not string "field_amount": 1500.50, // ✅ Correct "field_count": "25", // ❌ Wrong - string
// Boolean fields - actual boolean "field_approved": true, // ✅ Correct "field_complete": "true", // ❌ Wrong - string
// Date fields - ISO format "field_deadline": "2024-03-15", // ✅ Correct "field_due_date": "March 15, 2024", // ❌ Wrong "field_timestamp": "2024-03-15T10:30:00Z" // ✅ Also correct};
Select field validation:
// Get valid options firstconst task = pm.response.json();const priorityField = task.fields.find(f => f.id === "field_priority");console.log("Valid options:", priorityField.options);
// Then use exact matchconst captures = { "field_priority": "High" // Must match exactly};
Advanced validation script:
// Pre-request validationconst captures = JSON.parse(pm.request.body.raw).captures;const validationErrors = [];
// Type checkingObject.entries(captures).forEach(([fieldId, value]) => { if (fieldId.includes("amount") && typeof value !== "number") { validationErrors.push(`${fieldId} must be numeric, got ${typeof value}`); } if (fieldId.includes("approved") && typeof value !== "boolean") { validationErrors.push(`${fieldId} must be boolean, got ${typeof value}`); }});
if (validationErrors.length > 0) { console.error("Validation errors:", validationErrors); throw new Error("Form validation failed");}
Required field detection:
// Auto-detect required fields from task schemaconst task = pm.response.json();const requiredFields = task.fields .filter(f => f.required) .map(f => f.id);
console.log("Required fields:", requiredFields);
// Validate all required fields are presentconst captures = pm.variables.get("taskCaptures");const missingRequired = requiredFields.filter(fieldId => !captures.hasOwnProperty(fieldId) || captures[fieldId] === null);
if (missingRequired.length > 0) { console.error("Missing required fields:", missingRequired);}
With task automation mastered:
Postman > Working with templates and processes
How To > Ensure everyone in your team completes an approval or task
- 2025 Tallyfy, Inc.
- Privacy Policy
- Terms of Use
- Report Issue
- Trademarks