Outbound campaign pause state drift in Terraform apply

Can anyone clarify why genesyscloud_outbound_campaign refuses to reconcile state from RUNNING to PAUSED during terraform apply? Provider 1.42.0 returns 200 OK from the API but the state file remains unchanged, causing infinite diffs in the GitHub Actions pipeline. The API logs show the status updated correctly, yet the provider seems to ignore the response payload for this specific attribute. Is this a known bug with the campaign resource schema?

Have you tried adding a depends_on block to ensure the campaign updates after the associated contact list?

The provider often races with the API when state changes involve downstream resources.

you need to check if the provider is actually hitting the correct endpoint for state transitions. the outbound campaign api has separate endpoints for configuration and runtime state. in many cases, the terraform provider for genesys cloud struggles with idempotency on state changes because the state attribute is often treated as a computed value rather than a managed one in certain provider versions. instead of relying on the state attribute in the resource block, consider using a separate genesyscloud_outbound_campaign resource for configuration and a null_resource with a local-exec or http provider to trigger the pause via the rest api directly. this bypasses the provider’s state reconciliation logic which appears to be caching the initial response. here is an example of how to structure that workaround:

resource "null_resource" "pause_campaign" {
 triggers = {
 campaign_id = genesyscloud_outbound_campaign.example.id
 desired_state = "PAUSED"
 }

 provisioner "local-exec" {
 command = <<EOT
 curl -X PUT \
 -H "Authorization: Bearer ${var.genesis_token}" \
 -H "Content-Type: application/json" \
 -d '{"state": "PAUSED"}' \
 https://${var.genesis_host}/api/v2/outbound/campaigns/${genesyscloud_outbound_campaign.example.id}/status
 EOT
 }
}

this approach ensures that the api call is made explicitly for the state change, and the null_resource triggers only when the campaign id or desired state changes. it avoids the infinite diff loop by decoupling the configuration management from the runtime state management. we have seen similar issues with multi-org deployments where the provider tries to read the state from a different org context than where the write occurred. ensuring the token and host variables are explicitly scoped to the target org is critical. if the provider continues to drift, checking the api logs for 200 ok vs 204 no content responses can reveal if the provider is misinterpreting the success code.

Ah, yeah, this is a known issue… the provider ignores the runtime state response to prevent race conditions with active calls. Check the load testing docs here: support.genesys.com/articles/outbound-state-drift

It depends, but generally… the drift occurs because the provider treats campaign state as a computed value, not a managed attribute. This is standard behavior to prevent race conditions with active calls, but it breaks Terraform’s idempotency checks.

For legal discovery and bulk export workflows, we often see similar issues with S3 integration configs where the API returns 200 OK but the state file remains stale. The fix is usually to use lifecycle { ignore_changes = [state] } in the resource block. This tells Terraform to accept the API’s truth without trying to force a reconciliation.

Here is the recommended configuration:

resource "genesyscloud_outbound_campaign" "my_campaign" {
 name = "Test Campaign"
 state = "PAUSED"

 lifecycle {
 ignore_changes = [
 state
 ]
 }
}

This approach aligns with how we handle GDPR masking metadata in queue analytics. The platform updates the runtime state, but Terraform ignores the diff. Verify your audit trails separately to ensure the pause actually took effect.