Outbound Campaign API 400 on List ID Reference in Terraform

Trying to make sense of why the Genesys Cloud Terraform provider (v2.1.0) returns a 400 Bad Request when referencing an existing Contact List ID in an Outbound Campaign resource.

The deployment pipeline runs via GitHub Actions using GC CLI v1.5.4 for authentication. The Contact List is created in a separate module and its ID is passed as an output variable to the Campaign module. The ID format is valid UUID.

Error log from terraform apply:

Error: POST /api/v2/outbound/campaigns failed with 400
Body: {
“code”: “badRequest”,
“status”: 400,
“message”: “Invalid listId provided. List must be associated with the same organization.”
}

Both resources are deployed to the same Org ID. Verified via API explorer that the Contact List exists and is active. The JSON payload generated by Terraform looks correct:

resource “genesyscloud_outbound_campaign” “primary” {
name = “QA_Test_Campaign”
contact_list_id = var.contact_list_id
strategy_id = “default”
status = “paused”
}

Checked the raw HTTP request in debug logs. The header contains correct Bearer token and Org ID. No CORS issues. The endpoint /api/v2/outbound/campaigns expects a listId that matches an outbound contact list.

Is there a specific permission scope required for the service account used in the pipeline? The role assigned is ‘Outbound Manager’ and ‘Contact List Admin’.

Also noticed that if I create the campaign manually in the UI with the same list ID, it works fine. The issue seems isolated to the API call made by the Terraform provider during the initial creation step.

Any known issues with list ID validation in provider v2.1.0? Or is this a timing issue where the list ID is not fully propagated before the campaign resource attempts to link it? Adding a null_resource with local-exec to sleep for 30 seconds before applying the campaign might help, but looking for a cleaner solution using depends_on or data sources if possible.

Environment:

  • Terraform v1.6.0
  • Genesys Cloud Provider v2.1.0
  • GC CLI v1.5.4
  • Region: ap-southeast-2

Any insights appreciated.

To fix this easily, this is to bypass the Terraform provider’s implicit serialization for outbound resources. The GC API often rejects nested object references in campaign definitions if they are not fully resolved.

Switching to a direct REST API call via a ServiceNow Data Action or a custom script ensures the Contact List ID is passed as a clean string, avoiding the 400 error caused by the provider’s JSON mapping logic.

I normally fix this by:

  • Verifying the contact list ID is explicitly cast to a string in the Terraform variable definition to prevent type coercion errors during API serialization.
  • Checking that the outbound campaign module waits for the contact list module to complete using depends_on to ensure the resource exists before the reference is resolved.

Make sure you verify that the Contact List ID is not just a string, but actually points to a resource that Genesys Cloud can resolve at the moment of deployment. The suggestion above about depends_on is spot on, but coming from a Zendesk migration background, I have seen this exact 400 error when the underlying list isn’t fully indexed yet. In Zendesk, tags and groups are often available instantly, but in Genesys Cloud, there is a slight propagation delay for outbound resources. If Terraform moves too fast, the campaign tries to bind to a list that technically exists in the database but isn’t ready for association.

The fix is rarely about the Terraform syntax itself, but rather the state management. You should add a depends_on block in your genesyscloud_outbound_campaign resource that explicitly references the genesyscloud_outbound_contactlist resource. This forces Terraform to wait until the list is fully created and stable. Also, check if the list is being created in a different org or if there are permission issues with the service account used by the GC CLI. Sometimes the 400 is a mask for a 403 if the service account doesn’t have the correct outbound permissions.

Here is how the dependency should look in your HCL:

resource "genesyscloud_outbound_campaign" "my_campaign" {
 name = "Migration Test"
 contact_list_id = genesyscloud_outbound_contactlist.my_list.id
 
 depends_on = [
 genesyscloud_outbound_contactlist.my_list
 ]
}

This ensures the order of operations matches the system’s readiness. It is a small detail, but it prevents the race condition that causes the 400.