Skip to main content

How to Sync Salesforce with Worklog Systems Without Duplicate Tasks

About Us
Published by yuliya.dzemidchuk
23 June 2026

Salesforce Integration with work tracking external service

 

Introduction

Modern Salesforce implementations rarely stand alone. Whether managing HR processes, client onboarding, or project delivery, there is almost always a need to propagate data to external systems — ticketing platforms, worklog trackers, project management tools. One such integration point is Weenvo, a task and worklog service used to track project work, assign responsibilities, and log time.

This article covers the practical patterns and pitfalls developers encounter when connecting Salesforce to an external task service. The examples are drawn from real implementation experience: automatically creating Weenvo tasks when interview records change status in Salesforce, assigning the right people, setting estimates, avoiding duplicate task creation, and handling failures gracefully.

The patterns described here are not specific to Weenvo — the same architecture applies to any external task or worklog system. The goal is to provide a reproducible blueprint that any Salesforce developer can adapt.

 

When to Create External Tasks

The first design decision is identifying the exact moment a task should be created. In a Salesforce-to-Weenvo integration, task creation is typically triggered by a status transition on a Salesforce record — for example, an Interview record moving to the "Scheduled" status.

Salesforce Apex Triggers are the standard entry point. The trigger fires on record update, inspects the old and new field values, and initiates the external call when the correct transition is detected. The trigger itself should contain no business logic: its only job is to detect the relevant change and hand off to a handler class.

Two categories of status transitions commonly drive task creation:

Status transitions on a parent record — the Interview moves from "New"  to "Scheduled", triggering tasks for all assigned interviewers.

Cascading transitions on child records — an approval record is inserted or updated, triggering a notification task for a specific person.

Queueable Apex is the mechanism for asynchronous HTTP callouts. When the trigger fires, it enqueues a job — passing in the record IDs or data the job will need. The job then runs after the transaction commits, constructs the API payload, and sends the request to Weenvo.

This separation has several important benefits: it avoids callout limits in triggers, it allows the job to be retried independently, and it keeps the trigger thin and testable.

 

Constructing the Task Payload

The Weenvo API expects a structured JSON payload for task creation. Getting this payload right is where most of the integration-specific logic lives. The fields that require particular attention are: task type, status, assignee, watchers, and time estimate.

External task systems identify task types and statuses with internal numeric or UUID identifiers, not human-readable strings. These IDs are environment-specific — the "Interview" task type might have ID 42 in production and ID 17 in the sandbox. This creates a maintenance problem if the IDs are hardcoded in Apex classes.

The correct approach is to store these IDs in Custom Metadata. Custom Metadata records are deployable (they travel with Change Sets and SFDX packages), queryable in Apex without SOQL governor limits, and editable by admins without code changes.

Configuration Value

Storage Recommendation

Weenvo API base URL

Custom Metadata (Project__Setting_mdt)

API Key/Bearer token

Named Credential

Task Type IDs (Task, Bug, Story etc.)

Custom Metadata

Status IDs (Open, In progress, Closed etc.)

Custom Metadata

Assignee contact IDs in Weenvo

Contact object’s custom field

Project Keys

Custom Metadata

 

API credentials — bearer tokens, client secrets, API keys — must never appear in Apex code or Custom Metadata values. The correct storage mechanism is a Salesforce Named Credential.

A Named Credential stores the endpoint URL and authentication details in the Salesforce credential store, separate from code. The Apex class references the Named Credential by its developer name. When the token rotates, an admin updates the Named Credential record; no code deployment is required.

Weenvo identifies users by their Weenvo-internal contact IDs, which bear no relationship to Salesforce User IDs. A mapping layer is required. The mapping lives in Custom Metadata: a record per person, linking a Salesforce role or name to the corresponding Weenvo contact ID.

At runtime, the Queueable job looks up the Custom Metadata to resolve the Salesforce record's assigned user to a Weenvo contact ID before constructing the payload.

Many task systems support watchers — people who receive notifications about a task without being its primary assignee. In the Weenvo integration, watchers typically include the HR manager, team lead, or process owner.

Watcher IDs are stored in Custom Metadata alongside assignee IDs. The Queueable job collects the relevant watcher IDs and passes them as an array in the payload. An important rule: duplicate watcher IDs cause API errors on some platforms, so the code deduplicates the list before sending. In Apex, a Set is the idiomatic tool for this.

The task estimate is typically derived from a Salesforce field on the record — for example, the planned duration of an interview slot in minutes. When multiple assignees receive separate tasks (one task per interviewer), each task's estimate is set to the planned interview duration, since each interviewer independently commits that full block of time. 

 

Preventing Duplicate Task Creation  

Duplicate external task creation is one of the most common and disruptive problems in this type of integration. A re-save of the record, a Flow re-execution, or a bulk data operation can re-trigger the task creation logic and create duplicate Weenvo tasks that require manual cleanup.

Triggers fire on every record update, not just on the specific field transition that should trigger a task. If the guard logic is not precise, any save on the record re-runs the callout. Additionally, bulk operations can update hundreds of records in a single transaction, each independently triggering the Queueable enqueue.

The most reliable deduplication strategy is a lookup on Salesforce records: before creating a task, query whether one already exists. The pattern works as follows:

  • When a Weenvo task is successfully created, store the Weenvo task ID in a field on the Salesforce record (for example, a text field called External_Task_Id__c on the Interview object).
  • In the Queueable job, before calling the API, check whether that field is already populated.
  • If the field is populated, skip the callout — the task already  exists.
     

This approach is robust because it survives re-saves, retries, and bulk operations. The check is a simple SOQL query, not a complex state machine.

At the trigger level, the transition check itself is a deduplication guard: the code compares the old value of the status field to the new value, and only proceeds if the transition matches the expected pattern (for example, old value is not "Scheduled" and new value is "Scheduled"). Re-saves that do not change the status field do not pass this check and do not enqueue a job.

In bulk scenarios where many records are updated in one transaction, a static Boolean variable on the handler class can prevent the same logic from executing multiple times within a single Apex transaction. The variable is set to true after the first execution; subsequent calls in the same transaction are skipped. This is a standard Salesforce pattern for preventing trigger recursion.

 

Handling Subtasks

Some business processes require not a single Weenvo task but a parent task with multiple subtasks. A common example is an interview process: a parent task is created for the interview event, and a subtask is created for each interviewer, pre-filled with that interviewer's specific description, estimate, and feedback URL.

Subtasks in Weenvo require the parent task ID to exist before they can be created. This means the integration must create the parent task in one API call, extract the returned task ID from the response, and then create each subtask in subsequent calls referencing that parent ID.

This sequential dependency is best handled within a single Queueable job: the job creates the parent, parses the response, and iterates over the list of subtask definitions. If the parent creation fails, the subtasks are not attempted.

Each subtask receives a tailored description that includes the assignee's role, the interview details, and a direct URL to the Weenvo feedback form. Generating this description dynamically from Salesforce record data (rather than hardcoding it) makes the integration maintainable as business requirements change.

 

Failure Risks and How to Track Them

External API calls can fail for reasons entirely outside of Salesforce: network timeouts, third-party downtime, authentication expiry, rate limits, or malformed responses. A Weenvo integration without failure tracking creates invisible gaps — tasks that were supposed to exist simply do not, with no record of the failure.

Failure Type

Typical Cause

Frequency

HTTP timeout

Weenvo slow or unreachable

Low but unpredictable

401 Unauthorized

Named Credential token expired or rotated

Rare, high impact

400 Bad Request

Payload validation error (wrong type ID, missing field)

Common during initial setup

503 Service Unavailable

Weenvo maintenance or outage

Rare

Apex CPU/heap limit

Bulk operation with complex payload generation

Low

Duplicate key error

Callout attempted with already-existing watcher/assignee ID

Common without deduplication


The most reliable tracking mechanism is a dedicated Salesforce custom object for integration logs — for example, External_Task_Log__c. Every callout, successful or not, writes a record with the following fields:

  • The Salesforce record ID that triggered the callout
  • The HTTP status code returned
  • The full response body (or the error message)
  • The timestamp
  • The Weenvo task ID if creation succeeded

This log is queryable, reportable, and visible to admins without requiring a code deployment. A simple Salesforce report can surface all failed callouts from the past 24 hours.

Queueable jobs that fail do not automatically retry. Two approaches are practical:

  • Scheduled retry: a scheduled Apex job runs periodically (for example, every 30  minutes) and re-enqueues Queueable jobs for any log records that show a failure status and do not yet have a Weenvo task ID. The logic of repeated jobs may work differently depending on the error code. For example, if the error code is 401 (the credits are incorrect), then it is useless to repeat the process before making changes to them. And if the error is related to problems on the Weenvo server, a repeat request may be executed after a longer time than previously (1hr, 2hr, etc.). 
  • Manual retry via Flow or Quick Action: an admin-facing button on the Salesforce record re-triggers the Queueable enqueue on demand. This is useful for one-off failures caused by a temporary Weenvo outage.

Do not implement automatic infinite retries. A malformed payload will fail on every retry indefinitely, consuming governor limits and polluting logs. Limit automatic retries to a small number (two or three), then flag the record for manual review.

For high-stakes integrations, passive logging is not sufficient. Two alerting patterns are worth implementing:

  • Platform Event: the Queueable job publishes a Platform Event on failure. A Flow subscribes to the event and sends an email or Slack notification to the responsible team.
  • Scheduled report: a Salesforce report on the log object is scheduled to deliver daily to the integration owner. Any non-empty report indicates failures requiring attention.

 

JSON Parsing

Weenvo API responses must be parsed to extract the created task ID and any error details. Salesforce provides the JSON class for this, but for complex or variable-length responses, a dedicated parser utility class is worth building.

The parser utility centralizes the deserialization logic and handles edge cases: missing fields, unexpected null values, and partial failure responses where some subtasks were created and others were not. Keeping this logic in one class rather than duplicating it across multiple Queueable jobs makes future API contract changes easier to manage.

 

Deleting External Tasks

When a Salesforce record is deleted or its status rolls back, the corresponding Weenvo task may need to be deleted or cancelled. This is a separate integration concern from creation, and it carries its own risks.

The recommended pattern mirrors the creation pattern: a separate Queueable class handles the delete callout, reads the Weenvo task ID from the Salesforce record's External_Task_Id__c field, calls the Weenvo DELETE endpoint, and clears the field on success. If the Weenvo task ID field is empty, the job exits early — there is nothing to delete.


Deleting a Weenvo task that has already been completed or has logged work may violate audit requirements. Consider cancelling rather than deleting, or consulting the Weenvo API documentation for soft-delete options.

 

Testing Considerations

Unit testing an integration with an external HTTP service requires HTTP mock classes. Salesforce provides the HttpCalloutMock interface for this purpose. Test classes implement the mock, register it with Test.setMock(), and then exercise the Queueable class with controlled response payloads.

Two mock scenarios are essential:

  • Success mock: returns a 200 or 201 response with a valid Weenvo task ID in the body. Verifies that the Salesforce record is updated with the correct External_Task_Id__c value.
  • Failure mock: returns a 400 or 503 response. Verifies that the log record is written with the correct error status and that the Salesforce record is not updated with a task ID.

Integration tests against the live Weenvo sandbox should be run as part of release validation, but they should not be part of the daily CI pipeline — external dependencies make them unreliable for automated testing.

 

Conclusion

Integrating Salesforce with an external task service is straightforward in concept but requires deliberate engineering to be reliable in production. The patterns described in this article — Custom Metadata for configuration, Named Credentials for secrets, Queueable Apex for callouts, field-based deduplication, log objects for observability, and scoped retry logic — form a complete and maintainable baseline.

The most common failures in this type of integration are duplicated tasks caused by insufficient guards, and silent failures caused by missing error logging. Both are preventable with the approaches described above. Applied consistently, these patterns make the integration auditable, testable, and manageable without requiring code changes for routine configuration updates.


Alexander Zherebilo
Certified Salesforce Developer
image
Expertise
Question to the expert
image

We have available resources to start working on your project within 5 business days

1 UX Designer

image

1 Admin

image

2 QA engineers

image

1 Consultant

image
Related Articles
All articles
image
Is Salesforce Winning the Public Sector Race?
An analysis of Salesforce's rapid expansion into the U.S. public sector, tracing its path from cautious early government licensing deals in the 2010s through the launch of Government Cloud in 2012, its pivotal role in COVID-19 vaccine rollouts, and its 2025–2026 push into military and intelligence work via Agentforce and Missionforce. The piece covers major 2026 contracts — including a $5.6 billion Army deal, a $1.6 billion VA agreement, and Pentagon Impact Level 5 authorization — alongside real-world case studies like California's REAL ID processing and the UK's NHS back-office operations. It also examines the structural obstacles still facing Salesforce and other vendors in government tech: legacy IT systems decades old, outdated federal procurement rules, budget constraints, and organizational caution around AI adoption, plus the competitive pressure from Palantir, Microsoft, and Oracle in the race for public sector AI spending.
28 August 2026
image
Why Your Salesforce Flows Are Agentforce's Biggest Problem
This article argues that the most underestimated risk in Agentforce deployments isn't data quality — it's the automation layer: years of overlapping Flows, Process Builder processes, Apex triggers, and managed package logic that no one has reviewed end-to-end. It explains why AI agents inherit automation complexity without the tribal knowledge human admins carry, why technical debt only becomes visible after an agent hits it in production, and why a clean demo is no indicator of production readiness. The article closes with a concrete, tool-by-tool inventory approach using Flow Trigger Explorer, Salesforce Optimizer, Setup Audit Trail, Apex Debug Logs, Agent Builder, and Health Check — scoped to the specific processes the agent will actually use rather than the whole org.
23 July 2026
image
How to Wire Multiple Salesforce Projects in One Org Without Breaking Everything
This article maps the real integration patterns that emerge when multiple Salesforce projects — both managed packages and unpackaged code — share a single org. It covers four concrete patterns: attaching custom triggers to package-owned objects, calling global members exposed by managed packages, writing directly into another project's objects, and runtime-guarded reads of package data. It then addresses access control for authenticated and guest users, including the Master-Detail wall and the without sharing elevation pattern. The piece closes with eight concrete risks (compile-time dependencies that block uninstall, upgrade coupling, silent cascade failures, access invisible to admins) and six actionable recommendations for keeping cross-project coupling manageable.
08 July 2026