Outbound campaign POST 409 on list lock with dialer strategy binding

const campaignPayload = {
 name: "Q3_Cold_Outreach",
 type: "preview",
 dialerStrategy: { type: "predictive", targetRate: 65, maxAttempts: 3 },
 listIds: [targetListId],
 scriptId: mainScriptId,
 wrapUpCodes: ["sale", "not_interested", "callback_requested"],
 webhookUrl: "https://internal-metrics.ourdomain.com/gc/outbound"
};
const res = await fetch("/api/v2/outbound/campaigns", {
 method: "POST",
 headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
 body: JSON.stringify(campaignPayload)
});

Problem

The POST request bombs out the second the dialer strategy binds to the list reference, and Five9 handled these concurrent locks fine but the Genesys endpoint don’t play nice with overlapping references.

Error

409 Conflict - {"code":"conflict","message":"Campaign list reference is currently locked by active campaign."}

Question

Polling /api/v2/outbound/campaigns/{id} just spins on paused status while the webhook callback never fires for the transition event. The retry loop keeps timing out before the status updates.

Error: 409 Conflict.

List’s probably locked. Terraform’s drift check fails the same way if you skip this. Run the unlock call first.

{
 "locked": false
}

Make sure the list type matches the strategy.

The list lock issue usually stems from a mismatch in the Campaign Configuration rather than the raw API payload itself. Always prefer verifying this in the Admin UI over raw curl calls because the interface exposes the exact binding state. Checking the Admin UI under Outbound settings is the fastest way to confirm whether the Dialer Strategy actually matches the List Type. The unlock endpoint works fine, but you’ll still hit that 409 if the Campaign Configuration isn’t aligned with the current routing rules. Run the unlock request, verify the status flips to UNLOCKED in the Admin UI, and then resubmit the payload. The Throttle Configuration also needs to match the predictive rate you’re pushing, otherwise the edge drops the binding request outright. It’s messy when the backend expects a specific wrapper and the Admin UI hides it behind a dropdown. Queue Analytics will show the drop immediately if the binding fails. Watch the agent availability thresholds closely since predictive dialing burns through slots fast.

{
 "listId": "targetListId",
 "locked": false,
 "campaignConfiguration": {
 "strategy": "predictive",
 "targetRate": 65,
 "throttleConfiguration": {
 "maxConcurrentCalls": 50
 }
 }
}

That unlock step actually does the trick. The suggestion above about checking the Admin UI for the strategy-to-list binding is spot on. The 409 usually fires when the predictive dialer tries to grab a list flagged as exclusive to a preview campaign. You’ll want to hit the unlock endpoint first, then verify the dialer strategy type actually matches the list configuration. Lock states drift fast. Especially when you’re tweaking KB surfacing rules or chatbot handoff triggers.

Once that binding clears, the outbound triggers feed straight into the flow logic. The system needs a clean campaign state to properly route wrap-up codes into the agent assist panel. If the list stays locked, the auto-answer engine never gets the chance to surface those follow-up article suggestions to the rep. Handoffs also stall when the outbound session doesn’t close cleanly, leaving the customer hanging in the queue.

Try swapping type: "preview" to type: "progressive" in the payload if the list is meant for higher volume. The gateway constraint handles the routing headers a lot better that way. You can also run a quick GET on the list config to pull the current lockState before the POST. Saves a lot of trial and error.

sorry for the noob question. the unlock payload above looks right, but if you’re using the python sdk, make sure the path variable matches the list uuid. you’ll likely get a 404 if you mix them up.

api.update_list_lock(campaign_id=list_uuid, body={"locked": False}) # wrong param

scripts can lock silently too.