Symptoms
- Task History shows two or more executions of the same workflow a few seconds apart.
- The payloads are identical, including any primary key or record id your app sent.
- Your application logs show a single
POSTto the App Event endpoint, or a single event from the integration. - The Connected User has more than one configuration (or more than one connected account) for that integration, and the workflow is enabled on more than one of them.
Cause
App Events are one-to-many. One event can start every matching workflow for that Connected User. With Multi-Configuration, “matching” includes every configuration on the credential that has the workflow enabled. So if a user has three configurations, and two of them have “Create issue” enabled, one App Event produces two executions. The payloads look the same because they are the same event, applied to two configurations. The same fan-out applies to Integration Triggers. An “Issue Updated” (or similar) event from the provider is delivered to every configuration that has that workflow enabled. You cannot attach targeting headers to an inbound provider webhook. This is expected platform behavior. It is not a retry and not a duplicatePOST from your app.
Fix
App Events: target one configuration
Send the event to a single configuration. Pass both headers onPOST /projects/<Project ID>/sdk/events/trigger:
X-Paragon-Credential: the connected-account UUIDX-Paragon-Configuration-Id: the configuration UUID, orext:plus the external ID you assigned when creating the configuration
201. Sending only X-Paragon-Configuration-Id can return 400 Bad Request.
Full steps, including how to read both IDs from GET /sdk/me or paragon.getUser(), are in How to send an App Event to a single configuration.
Integration Triggers: you cannot target the inbound event
The provider calls Paragon. There is no place to setX-Paragon-Configuration-Id. Use one of the following, or combine them.
Enable the workflow on only one configuration. Leave it disabled on the others. You can do this in the Connect Portal for that configuration, or with paragon.enableWorkflow / paragon.disableWorkflow and selectedConfigurationId (Multi-Configuration).
Give each configuration a required User Setting that uniquely identifies it, then use that setting in the workflow so only the matching configuration proceeds. Examples: a project key, issue type, folder, or assignee. Add the setting under Customize Connect Portal > Configuration, mark it required, and reference it from a Conditional step or from the trigger’s own filters (for example a JQL query that includes {{settings.project}}). See User Settings.
Make the workflow idempotent. Before creating or updating a record in your app, check whether that provider record was already synced. Extra executions then become no-ops.
Untargeted duplication is the default. Multi-Configuration is for cases where each configuration should run with its own settings (different folders, projects, or teams), or where you have already constrained the trigger so each configuration only matches its own events.
Prevention
- When you send App Events, always include both targeting headers if the user can have more than one configuration.
- Do not enable the same unfiltered Integration Trigger workflow on every configuration unless you want one execution per configuration.
- Prefer User Settings that make each configuration’s trigger unique (project, issue type, folder, channel) over relying on users to avoid “duplicate” configurations.
- If you also use Multi-Account Authorization, one event can run once per connected account as well. Pass
X-Paragon-Credential(and a configuration ID when you use Multi-Configuration) instead of leaving the event untargeted.
Still having issues?
Send support:- The workflow Task History IDs for the duplicate runs, and the time gap between them
- Whether the trigger is an App Event or an Integration Trigger
- How many configurations (and connected accounts) the user has, and which of them have the workflow enabled
- For App Events: the request URL, whether you sent
X-Paragon-CredentialandX-Paragon-Configuration-Id, and the exact header values (configuration UUID vsext:+ external ID) - For
400on the App Event endpoint: the response body, and whether the same request succeeds with those headers removed