> ## Documentation Index
> Fetch the complete documentation index at: https://docs.operata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy the Operata AWS stacks with Terraform

> Deploy the Operata Cloud Collector v3 stacks into your AWS account using Operata's pre-synthesized Terraform JSON files.

Deploy the full suite of Operata Cloud Collector v3 stacks with Terraform.
Operata publishes pre-synthesized Terraform JSON files (`.tf.json`) — you
download one file per stack, set a handful of variables, and run
`terraform apply`. You need Terraform and AWS credentials, nothing else. There's
no CDK, npm, or other build tooling involved.

Before you start, know that:

* Each stack takes around 5–15 minutes to deploy.
* Terraform state is stored locally by default. For team environments, configure
  a remote backend (S3, for example) before you deploy.
* Keep your Operata API key out of version control — pass it inline or store it
  in a secrets manager.

## Before you start

| Requirement         | Notes                                                                                                                                                                                                     |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Terraform           | v1.8 or later — [install guide](https://developer.hashicorp.com/terraform/install). The templates don't set `required_version`, so an older CLI isn't blocked, but Operata tests against 1.8 and up.      |
| AWS provider        | Pinned to exactly `5.100.0` in `required_providers`, not a range. If you run a provider mirror or an air-gapped registry, stock that version before you run `terraform init`.                             |
| AWS credentials     | In the target account, with permission to create IAM, Lambda, Kinesis, EventBridge, Secrets Manager, and CloudWatch Logs resources — and, for `clrules`, CloudFormation and Amazon Connect rule resources |
| Operata Group ID    | [How to find your Operata Group ID](/docs/help/how-to-find-my-operata-group-id)                                                                                                                           |
| Operata API key     | [How to create an API key](/docs/api-authentication)                                                                                                                                                      |
| Terraform templates | Download one per stack from [Available stacks](#available-stacks) below.                                                                                                                                  |

## Available stacks

Stacks are independent — deploy them in any combination.

| Stack                       | What it collects                                                                                                        | Template                                                                                                                     | VPC variant                                                                                                                      |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Contact Trace Records (CTR) | CTR data from your Amazon Connect Kinesis stream                                                                        | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-trace-records.tf.json) | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-trace-records-vpc.tf.json) |
| Contact Lens Data (CLD)     | Contact Lens output from S3                                                                                             | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-data.tf.json)     | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-data-vpc.tf.json)     |
| Contact Flow Logs (CFL)     | Contact flow logs from CloudWatch                                                                                       | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-flow-logs.tf.json)     | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-flow-logs-vpc.tf.json)     |
| Lex V2 Logs                 | Lex V2 conversation logs from CloudWatch                                                                                | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-lexv2-logs.tf.json)            | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-lexv2-logs-vpc.tf.json)            |
| Contact Lens Rules (CLR)    | Real-time and post-call Contact Lens rules, deployed into your Amazon Connect instance via nested CloudFormation stacks | [Download](https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-rules.tf.json)    | —                                                                                                                                |

<Note>
  Choose a VPC variant only if your AWS account requires Lambda functions to run
  inside a VPC — typically enterprise or regulated environments. VPC variants
  take two extra variables: a VPC ID and a list of private subnet IDs. If you're
  not sure which you need, ask whoever manages your AWS account. The standard
  (non-VPC) variant is usually the right choice.
</Note>

## Deploy a stack

Deploy only the stacks you need, in any order. Each section below is a
complete, ready-to-run deploy block. Fill in your own values — Group ID, API
key, ARNs, and log group names — before you run it.

<Warning>
  Resource names are fixed. Every template hard-codes `prod` into its secret
  names, resource names, and — for `clrules` — its CloudFormation stack name.
  There's no environment variable to set. Deploying the same stack twice into
  one AWS account and region collides on those names.
</Warning>

### Contact Trace Records (CTR)

```bash theme={null}
mkdir -p ~/operata/ctr
cd ~/operata/ctr
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-trace-records.tf.json
cat > terraform.tfvars <<EOF
aws_region                     = "ap-southeast-2"
operata_group_id               = "<your-operata-group-id>"
operata_api_key                = "<your-operata-api-key>"
ctr_kinesis_stream_arn         = "arn:aws:kinesis:ap-southeast-2:111111111111:stream/..."
connect_instance_friendly_name = "Prod"
agent_data_s3_bucket_name      = ["", ""]
EOF
terraform init
terraform apply
```

The pipe filters on `{ "data": { "Channel": ["VOICE"] } }`, so it forwards
voice contacts only. Chat and task contacts never reach Operata. See
[IAM policies](/docs/iam-policies) for the full pipe configuration.

`agent_data_s3_bucket_name` takes a two-element list in the format
`["bucket-name", "prefix/"]`. Enter those values if you have an agent data S3
bucket set up. Otherwise leave it as `["", ""]`.

To remove the stack, run `terraform destroy`.

For the VPC variant:

```bash theme={null}
mkdir -p ~/operata/ctr-vpc
cd ~/operata/ctr-vpc
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-trace-records-vpc.tf.json
cat > terraform.tfvars <<EOF
aws_region                            = "ap-southeast-2"
operata_group_id                      = "<your-operata-group-id>"
operata_api_key                       = "<your-operata-api-key>"
ctr_kinesis_stream_arn                = "arn:aws:kinesis:ap-southeast-2:111111111111:stream/..."
connect_instance_friendly_name        = "Prod"
agent_data_s3_bucket_name             = ["", ""]
enrichment_lambda_vpc_id              = "vpc-0123456789abcdef0"
enrichment_lambda_vpc_private_subnets = ["subnet-aaaa", "subnet-bbbb"]
EOF
terraform init
terraform apply
```

### Contact Lens Data (CLD)

```bash theme={null}
mkdir -p ~/operata/cld
cd ~/operata/cld
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-data.tf.json
cat > terraform.tfvars <<EOF
aws_region                       = "ap-southeast-2"
operata_group_id                 = "<your-operata-group-id>"
operata_api_key                  = "<your-operata-api-key>"
contact_lens_data_s3_bucket_name = "<your-contact-lens-bucket>"
EOF
terraform init
terraform apply
```

To remove the stack, run `terraform destroy`.

For the VPC variant:

```bash theme={null}
mkdir -p ~/operata/cld-vpc
cd ~/operata/cld-vpc
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-data-vpc.tf.json
cat > terraform.tfvars <<EOF
aws_region                                       = "ap-southeast-2"
operata_group_id                                 = "<your-operata-group-id>"
operata_api_key                                  = "<your-operata-api-key>"
contact_lens_data_s3_bucket_name                 = "<your-contact-lens-bucket>"
s3_kinesis_integrator_lambda_vpc_id              = "vpc-0123456789abcdef0"
s3_kinesis_integrator_lambda_vpc_private_subnets = ["subnet-aaaa", "subnet-bbbb"]
EOF
terraform init
terraform apply
```

### Contact Flow Logs (CFL)

`cf_log_group` is the CloudWatch log group Amazon Connect delivers flow logs
to — `/aws/connect/<your-instance-alias>`. Find yours in the CloudWatch
console, or see [Contact flow logs](/docs/contact-flow-logs).

```bash theme={null}
mkdir -p ~/operata/cfl
cd ~/operata/cfl
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-flow-logs.tf.json
cat > terraform.tfvars <<EOF
aws_region                     = "ap-southeast-2"
operata_group_id               = "<your-operata-group-id>"
operata_api_key                = "<your-operata-api-key>"
cf_log_group                   = "/aws/connect/operata-prod"
connect_instance_friendly_name = "Prod"
EOF
terraform init
terraform apply
```

To remove the stack, run `terraform destroy`.

For the VPC variant:

```bash theme={null}
mkdir -p ~/operata/cfl-vpc
cd ~/operata/cfl-vpc
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-flow-logs-vpc.tf.json
cat > terraform.tfvars <<EOF
aws_region                             = "ap-southeast-2"
operata_group_id                       = "<your-operata-group-id>"
operata_api_key                        = "<your-operata-api-key>"
cf_log_group                           = "/aws/connect/operata-prod"
connect_instance_friendly_name         = "Prod"
cfl_decoder_lambda_vpc_id              = "vpc-0123456789abcdef0"
cfl_decoder_lambda_vpc_private_subnets = ["subnet-aaaa", "subnet-bbbb"]
EOF
terraform init
terraform apply
```

### Lex V2 Logs

```bash theme={null}
mkdir -p ~/operata/lexv2
cd ~/operata/lexv2
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-lexv2-logs.tf.json
cat > terraform.tfvars <<EOF
aws_region         = "ap-southeast-2"
operata_group_id   = "<your-operata-group-id>"
operata_api_key    = "<your-operata-api-key>"
lex_log_group_name = "/aws/lex/<your-bot>/conversation-logs"
EOF
terraform init
terraform apply
```

To remove the stack, run `terraform destroy`.

For the VPC variant:

```bash theme={null}
mkdir -p ~/operata/lexv2-vpc
cd ~/operata/lexv2-vpc
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-lexv2-logs-vpc.tf.json
cat > terraform.tfvars <<EOF
aws_region                                = "ap-southeast-2"
operata_group_id                          = "<your-operata-group-id>"
operata_api_key                           = "<your-operata-api-key>"
lex_log_group_name                        = "/aws/lex/<your-bot>/conversation-logs"
lex_enrichment_lambda_vpc_id              = "vpc-0123456789abcdef0"
lex_enrichment_lambda_vpc_private_subnets = ["subnet-aaaa", "subnet-bbbb"]
EOF
terraform init
terraform apply
```

### Contact Lens Rules (clrules)

Deploy this stack if your Operata configuration uses Contact Lens event
processing. `clrules` deploys two sets of Amazon Connect rules into your
instance — one for real-time Contact Lens analysis and one for post-call.

This Terraform stack wraps the Operata Contact Lens Rules CloudFormation
template in an `aws_cloudformation_stack` resource. Running `terraform apply`
provisions a nested CloudFormation stack named
`operata-contact-lens-rules-prod` in your account, which in turn creates the
Connect rules.

```bash theme={null}
mkdir -p ~/operata/clrules
cd ~/operata/clrules
curl -O https://operata-customer-assets.s3.amazonaws.com/ccv3-templates/cloud-collector-v3-contact-lens-rules.tf.json
cat > terraform.tfvars <<EOF
aws_region                  = "ap-southeast-2"
amazon_connect_instance_arn = "arn:aws:connect:ap-southeast-2:111111111111:instance/<your-instance-id>"
EOF
terraform init
terraform apply
```

The apply takes around 25 seconds. Rule creation is serialized to respect the
Amazon Connect `CreateRule` API rate limit of 2 requests per second.

Confirm the rules landed:

```bash theme={null}
aws connect list-rules \
  --region ap-southeast-2 \
  --instance-id <your-instance-id> \
  --publish-status PUBLISHED \
  --query 'RuleSummaryList[?starts_with(Name, `operata_`)] | length(@)'
```

To remove the stack, run `terraform destroy`. `clrules` creates no AWS Secrets
Manager secrets, so no force-deletion step is required afterwards.

## Verify

### 1. Place a test contact

Make or receive a short test call in your Amazon Connect instance. On an inbound
call, **close the contact** before you check for data, or it won't appear. Data
can take up to five minutes to reach Operata after the call ends.

### 2. Check API activity

Open **Group Settings → Integrations → API Management** and look for a recent
**Last Used** timestamp on the API key.

* **Recent activity** — your stack is sending data. Continue to step 3.
* **No recent activity** — stop here. Check that `operata_api_key` and
  `operata_group_id` in your `terraform.tfvars` match your Operata account, then
  test again. If there's still no activity, contact Operata support.

### 3. Check the data view for your stack

* **CTR** — open **Calls and Logs → Details / Summary** and confirm the test
  call appears.
* **Contact Lens (CLD)** — open **Dashboards → Conversational Analytics** and
  confirm data appears. Filter by the test agent's name or sort by most recent
  call.

If nothing appears after 10 minutes, work through
[Troubleshooting](#troubleshooting).

## Upgrade an existing stack

To apply a newer Operata release to a stack you've already deployed:

1. Download the new `.tf.json` file into the same working directory, replacing
   the previous file. Filenames carry no version tag, so the latest release is
   always at the same URL.
2. Run `terraform plan` and confirm only the expected resources change —
   typically the Lambda zip key and a few metadata fields.
3. Run `terraform apply`.

<Warning>
  If unexpected resources appear in the plan, contact Operata before you
  continue.
</Warning>

State in the working directory tracks resource identity, so the upgrade happens
in place. Terraform doesn't replace the EventBridge pipe, the Kinesis stream, or
the IAM resources. For `clrules`, `terraform apply` triggers a CloudFormation
stack update on the nested `operata-contact-lens-rules-prod` stack, which diffs
and updates only the changed rules.

Each stack upgrades independently. Collection pauses for roughly 2–5 minutes per
stack while the apply runs, and calls handled in that window don't reach
Operata — so schedule upgrades outside peak contact center hours where you can.

## Redeploy after a destroy

AWS Secrets Manager schedules secrets for deletion with a 30-day recovery
window — `terraform destroy` doesn't remove them immediately. Run
`terraform apply` again before that window expires and the apply fails with:

```
InvalidRequestException: You can't create this secret because a secret with this name is already scheduled for deletion.
```

To unblock an immediate redeploy, force-delete the affected secrets after the
destroy:

```bash theme={null}
aws secretsmanager delete-secret \
  --region ap-southeast-2 \
  --secret-id /cloud-collector-v3/ctr/apiToken-prod \
  --force-delete-without-recovery
```

<Warning>
  `--force-delete-without-recovery` removes the secret permanently. Use it only
  when you intend to recreate it immediately.
</Warning>

Secrets created per stack:

| Stack       | Secrets                                                                                      |
| ----------- | -------------------------------------------------------------------------------------------- |
| `clrules`   | None                                                                                         |
| CTR         | `/cloud-collector-v3/ctr/apiToken-prod`                                                      |
| CLD         | `/cloud-collector-v3/cld/apiToken-prod`                                                      |
| CFL         | `/cloud-collector-v3/cfl/apiToken-prod`, `/cloud-collector-v3/cfl/redactionPolicyCache-prod` |
| Lex V2 Logs | `/cloud-collector-v3/lex/apiToken-prod`, `/cloud-collector-v3/lex/redactionPolicyCache-prod` |

## Troubleshooting

Work through these before you contact Operata support.

**EventBridge Pipe fails to create on the first apply.** This is an IAM
eventual-consistency issue. The role and policies are created correctly, but
EventBridge runs an upfront access check before IAM has finished propagating.
Run `terraform apply` again — Terraform leaves the role in place and retries
only the pipe.

**Secret already scheduled for deletion.** Force-delete the affected secrets
from the CLI (see [Redeploy after a destroy](#redeploy-after-a-destroy)), then
apply again.

**CLD deploys cleanly but no data appears in Operata.** The EventBridge Pipe
shows `RUNNING` but no Contact Lens summaries arrive. Check that Contact Lens is
enabled on your Amazon Connect instance and that calls run with Contact Lens
analysis turned on.

**Terraform `inline_policy` deprecation warning.** Terraform may print a
deprecation warning on `aws_iam_role.inline_policy`. It's a provider-level
notice. The configuration applies cleanly and the warning has no functional
impact.

## Get help

If you hit an issue, or you're not sure which stacks or environment apply to
your setup, email [help@operata.com](mailto:help@operata.com) or send a message
from inside the Operata app.

## Related

* [Install CTR collection](/docs/ctr-installation) — the CloudFormation path for the same collector.
* [Install Contact Lens](/docs/contact-lens-installation) — Contact Lens prerequisites and configuration.
* [IAM policies](/docs/iam-policies) — the permissions each stack needs.
* [Troubleshoot the integration](/docs/aws-troubleshooting) — missing records, deployment failures, secret management.
