# Operate a Deployment

Prove that a change isn't configuration before you change code. Most change requests to an installed Connector are a value in its install form, and a redeploy applies them in minutes without a pull request, a tag, or a new validation run.

Zen Electron's marketing team asks for a different sender address on order confirmations, by tomorrow. By the end of this page, you can tell whether that needs a pull request, apply it, and confirm it. You can also move the Deployment to new code, diagnose the common failures, and remove the Connector cleanly.

This page applies step 2 of the [adoption ladder](/learning-integrate-with-commercetools/integration-essentials/choose-where-it-runs.md#the-adoption-ladder): before you decide a Connector falls short, check whether configuration closes the gap. It operates the `zen-order-confirmation-sandbox` Deployment from [Install and test your Connector](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md).

## Change request: a new sender address

The sender address isn't in the code. It's the `SENDER_EMAIL_ADDRESS` key in the `mail-sender` application's `securedConfiguration`, which the handler reads from the environment. The change is therefore a redeploy with a new value, not a pull request.

### What the redeploy does to the other values

The [Redeploy](/connect/deployments.md#redeploy) reference states that if you omit `configurationValues`, existing values are unchanged. Don't assume the same for individual keys: when you send some keys, treat the keys you omit as unknown.

Two rules keep the change safe:

- **Keep every secured value in your own secrets store.** Secured values can't be read back from the Deployment after they're set, so the store is the only place you can recover them from.
- **Send the full set of values, and never a placeholder for a secured key you can't recover.** Resending the full set from your secrets store works whether a redeploy merges or replaces.

For this module, the other values are stubs, so the examples that follow resend the full set with the new sender.

### With the Connect CLI

Replace the sender in the `CONFIG` array from [Stage, preview, and publish privately](/learning-integrate-with-commercetools/deploy-and-build-connectors/stage-preview-and-publish-privately.md), then pass the whole array:

```bash
CONFIG=("${CONFIG[@]/SENDER_EMAIL_ADDRESS=orders@example.com/SENDER_EMAIL_ADDRESS=confirmations@example.com}")

commercetools connect deployment redeploy 
  --key zen-order-confirmation-sandbox 
  "${CONFIG[@]}"
```

### With the Connect API

The Redeploy update action is the only update action on a Deployment. It also works on a `Failed` Deployment, so you can correct a bad configuration value without deleting the Deployment. The reference lists every state that it accepts. Use the token and variables from [Stage, preview, and publish privately](/learning-integrate-with-commercetools/deploy-and-build-connectors/stage-preview-and-publish-privately.md#before-you-start). Replace the sender in the `CONFIGURATIONS` array from [Stage, preview, and publish privately](/learning-integrate-with-commercetools/deploy-and-build-connectors/stage-preview-and-publish-privately.md), then send the whole array:

```bash
CONFIGURATIONS=$(jq 'map(.securedConfiguration |= map(
  if .key == "SENDER_EMAIL_ADDRESS" then .value = "confirmations@example.com" else . end))' <<< "$CONFIGURATIONS")

VERSION=$(curl -sS --fail-with-body "$CONNECT_URL/$CTP_PROJECT_KEY/deployments/key=zen-order-confirmation-sandbox" 
  -H "Authorization: Bearer $TOKEN" | jq .version)

jq -n --argjson version "$VERSION" --argjson configurations "$CONFIGURATIONS" '{
  version: $version,
  actions: [{ action: "redeploy", configurationValues: $configurations }]
}' | curl -sS --fail-with-body -X POST "$CONNECT_URL/$CTP_PROJECT_KEY/deployments/key=zen-order-confirmation-sandbox" 
  -H "Authorization: Bearer $TOKEN" 
  -H "Content-Type: application/json" 
  -d @- | jq '{status, version}'
```

### Scripts run again

A redeploy reruns `postDeploy` by default. The template's `postDeploy` deletes and recreates the Subscription, so Messages created during that gap aren't delivered. That's why [Implement and test the event app to the contract](/learning-integrate-with-commercetools/deploy-and-build-connectors/implement-and-test-the-event-app.md#lifecycle-scripts) asked for repeatable lifecycle scripts.

For a change that doesn't affect the Subscription, such as a sender address, you can add `--skipScripts` in the CLI, or `"skipScripts": true` in the API, to keep the Subscription as it is. Don't skip scripts when the change affects what `postDeploy` creates, such as a new Message type.

### Confirm the change

When the Deployment is `Deployed` again, import another Order as in [Trigger an Order](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md#trigger-an-order) and read the logs. The stub's line now shows the new sender:

```text
Email provider stub: email not sent {"sender":"confirmations@example.com","templateId":"order-confirmation","lineItemCount":1}
```

Marketing's request needed no pull request. If the change had been to the email's content or to which Orders get an email, it would have been code: a new version.

## Move to a new version

A code change reaches a running Deployment through the steps in [Update your Connector](/connect/getting-started.md#update-your-connector). Publishing runs the validation pipeline again, so a new tag can fail before any Deployment moves. With the CLI and the tag `v0.2.1`, the sequence is:

```bash
git tag v0.2.1 && git push origin v0.2.1

commercetools connect connectorstaged update 
  --key zen-order-confirmation 
  --repository-tag v0.2.1

commercetools connect connectorstaged publish --key zen-order-confirmation
# Wait until `connectorstaged describe` shows status Published.

commercetools connect deployment redeploy 
  --key zen-order-confirmation-sandbox 
  --updateConnector
```

If the Deployment still behaves the old way, one of the first three steps didn't land. Compare the tag that the Deployment runs with the tag of the published Connector and of the ConnectorStaged:

```bash
curl -sS --fail-with-body "$CONNECT_URL/$CTP_PROJECT_KEY/deployments/key=zen-order-confirmation-sandbox" 
  -H "Authorization: Bearer $TOKEN" | jq '{deployed: .connector.version, tag: .connector.repository.tag}'

curl -sS --fail-with-body "$CONNECT_URL/connectors/key=zen-order-confirmation" 
  -H "Authorization: Bearer $TOKEN" | jq '{published: .version, tag: .repository.tag}'

curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" 
  -H "Authorization: Bearer $TOKEN" | jq '{status, tag: .repository.tag, report: .publishingReport.entries}'
```

If the ConnectorStaged's tag is new but its `status` is `Failed`, read `publishingReport`: the new tag didn't pass the validation pipeline, so there's no new version to move to. If the published Connector has the new tag but the Deployment's tag is old, the redeploy ran without `updateConnector`.

## Read logs and reports

Connect gives you three views of a Deployment. Each answers a different question.

**Logs** show what your application wrote while it ran. [Use logs to debug a Deployment](/connect/how-to-debug-a-deployment.md#view-your-applications-logs) lists where to read them and how far back you can query. For Zen Electron's Connector, filter to the `mail-sender` application with `commercetools connect deployment logs --key zen-order-confirmation-sandbox --application mail-sender`. Logs are only as useful as what the application writes, which is why [Implement and test the event app to the contract](/learning-integrate-with-commercetools/deploy-and-build-connectors/implement-and-test-the-event-app.md) added the Message type, `resource.id`, and `sequenceNumber` to the success and failure lines for every decoded Message.

**Reports** show what Connect did while it built and deployed the application. Read them on the installation's **Build details** tab, or in the Deployment's `details.build.report.entries`:

```bash
curl -sS --fail-with-body "$CONNECT_URL/$CTP_PROJECT_KEY/deployments/key=zen-order-confirmation-sandbox" 
  -H "Authorization: Bearer $TOKEN" | jq '{status, report: .details.build.report.entries}'
```

Since 2 July 2026, the [report updates in real time](/connect/releases/2026-07-02-added-real-time-reports-for-validation-and-deployment-operations), and the release note says that a failed Deployment's report shows where and why it stopped. The report doesn't always explain why provisioning failed, so read the report first, then the logs, then the resources.

**Resources** show whether the Connector's lifecycle scripts did their job. `postDeploy` output might not appear in the Deployment logs, so query the Subscription, as in [Verify the resource, not the status](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md#verify-the-resource-not-the-status).

| Symptom | Look first at |
| --- | --- |
| Deployment `Failed` | The report, then the logs |
| Deployment `Deployed`, but no events arrive | The Subscription by key: exists, `Healthy`, expected Message types |
| Events arrive, but no email is requested | The logs for that `resource.id` |
| The provider has no record of an email that the logs say was handed over | The provider's activity log |
| New code isn't running | The Deployment's `connector.version` and the ConnectorStaged's `publishingReport` |

## Debug a failed Deployment

[How to debug a Deployment](/connect/how-to-debug-a-deployment.md) describes the general approach. The following scenarios are the ones this Connector is likely to hit.

### A configuration value is missing or rejected

Connect rejects a Deployment request that has keys `connect.yaml` doesn't declare, or that leaves a required global key empty. The [Create Deployment](/connect/deployments.md#create-deployment) and Redeploy references list these errors, such as `DeploymentUnknownApplicationConfigurationKey`.

A value that Connect accepts can still fail in the application. The template validates its configuration when it starts, and stops if a value is invalid. For example, a Deployment with placeholder API Client credentials can fail provisioning without a reason in its report. Check the configuration values against what the application validates on startup (`mail-sender/src/validators/env.validators.js`) before you change code.

### Two Deployments share one Subscription

Zen Electron creates a second Deployment of the same Connector in the same Project, for example a production Deployment next to the sandbox one. Later, the team deletes the sandbox Deployment, and the production Deployment stops receiving events.

The cause is the template's fixed Subscription key, `ct-connect-email-delivery-subscription`. The second Deployment's `postDeploy` deleted the first's Subscription and created one pointing at its own topic. Deleting the sandbox Deployment then ran `preUndeploy`, which deleted the Subscription by the same key, leaving the production Deployment with none.

To fix it, choose one of the following:

- **Run one Deployment per Project.** Delete the extra Deployment, then redeploy the remaining one so that `postDeploy` recreates its Subscription.
- **Derive the key from the Deployment**, for example from the injected topic name, so that each Deployment owns its own Subscription. This is a code change and a new version.

### The Region doesn't match

A Deployment fails with [`DeploymentUnsupportedRegion`](/connect/errors.md#deploymentunsupportedregion) when its Region isn't in the ConnectorStaged's `supportedRegions`, as [Choose the Region and environment](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md#choose-the-region-and-environment) explains. Add the Region to the ConnectorStaged's supported Regions, publish again, and deploy. Otherwise, deploy in the Project's Region unless you have a reason not to.

## Check Subscription health

A Subscription that exists can still stop delivering. Its `status` field reports health, and the [Get Health Status of Subscription](/api/projects/subscriptions.md#get-health-status-of-subscription-by-id) endpoint returns it. Alert on any status other than `Healthy` in production. Each health status has its own retry window, and notifications can be dropped when the window ends. The [Subscription delivery guarantees](/api/projects/subscriptions.md#at-least-once-delivery) list the windows. Resolve a `ConfigurationError` before its window ends, and don't rely on the separate [Connect broker retention for unacknowledged messages](/connect/deployment-behavior-and-environments.md#event) to extend it.

## Uninstall and confirm cleanup

Delete the Deployment:

```bash
commercetools connect deployment delete --key zen-order-confirmation-sandbox
```

The command waits at a `y/n` prompt. Deleting runs `preUndeploy`, which deletes the Subscription. Confirm it with the same query as in [Verify the resource, not the status](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md#verify-the-resource-not-the-status). The expected result is an empty list:

```bash
curl -sS --fail-with-body -G 
  "https://api.$CTP_REGION.commercetools.com/$CTP_PROJECT_KEY/subscriptions" 
  -H "Authorization: Bearer $TOKEN" 
  --data-urlencode 'where=key="ct-connect-email-delivery-subscription"' 
  | jq '.count'
```

A count of `1` means that `preUndeploy` didn't run or failed. Delete the Subscription by key yourself, or it keeps sending Messages to a topic with no consumer.

To remove the Connector itself, delete the ConnectorStaged with the Connect API after every Deployment of it is gone, as [Deleting a ConnectorStaged](/learning-integrate-with-commercetools/deploy-and-build-connectors/stage-preview-and-publish-privately.md#deleting-a-connectorstaged) describes.

A Connector with a `job` application can also override the job's schedule for each Deployment. See [Job](/connect/deployment-behavior-and-environments.md#job). The email Connector has no job application.

## Worked example: change Zen Electron's sender address

1. Confirm the request is configuration: `SENDER_EMAIL_ADDRESS` is a secured key, not code.
2. Redeploy `zen-order-confirmation-sandbox` with the full set of values and the new sender, using `--skipScripts` because the Subscription doesn't change.
3. Wait for `Deployed`, import an Order, and find `"sender":"confirmations@example.com"` in the stub's log line.

Marketing has its new sender address the same day, with no pull request, tag, or validation run.

## Key takeaways

- Check whether a change is configuration before you change code. A redeploy with new values applies it without a new version.
- The redeploy action leaves values unchanged when you omit `configurationValues`. Keep secured values in your own secrets store, because Connect can't return them.
- A redeploy reruns `postDeploy` unless you skip scripts. Skip them only when the change doesn't affect what the scripts create.
- A new version needs four steps: tag, set the repository, publish, and redeploy with `updateConnector`. If behavior doesn't change, compare versions and read the publishing report.
- Logs show what your application did, reports show what Connect did, and the resources show whether the lifecycle scripts worked. Check all three.
- A fixed Subscription key means two Deployments in one Project overwrite each other, and undeploying either removes the shared Subscription.
- After you uninstall, confirm that `preUndeploy` removed the Subscription.

## Related pages

- [Area overview page with navigation](/learning-integrate-with-commercetools.md)
- [Previous page: Install and test your Connector](/learning-integrate-with-commercetools/deploy-and-build-connectors/install-and-test-your-connector.md)
- [Next page: Extend it with AI (optional)](/learning-integrate-with-commercetools/deploy-and-build-connectors/extend-it-with-ai.md)
- [Search documentation and API specs](/search.md)