Stage, preview, and publish privately

Tag a release, create a ConnectorStaged, read the validation reports, and publish for your own Projects.

Ask about this Page
Copy for AI
View as Markdown

After completing this page, you should be able to:

  • Create a ConnectorStaged from a repository tag with the Connect CLI and the Connect API.

  • Read the validation pipeline steps and the preview and publishing reports.

  • Deploy a ConnectorStaged to preview, test it, and delete the preview Deployment.

  • Publish a Connector privately, and explain what certification adds.

Private publishing needs no certification. Certification only matters if you want a public listing on the Connect marketplace. What does gate a private Connector is the validation pipeline that runs when you request a preview or publish, and its report is the result you act on.

Zen Electron's team ran commercetools connect validate locally and saw critical findings. The preview request for the same tag passed. By the end of this page, you know which result to trust, and you have a privately published Connector ready to install.
This page applies the lifecycle from Choose where it runs and how to adopt it. You act as the Creator: you turn a repository tag into a ConnectorStaged, preview it, and publish it as a Connector. The next page installs it as a Client.

The Creator flow

A ConnectorStaged is the editable draft: a name, a creator, a repository URL, and a tag. A Connector is the read-only result of publishing it. You request a preview and publish through the ConnectorStaged, and every request runs the validation pipeline against the tag.
This page shows each step with the CLI first and the Connect API second. Connect workflow maps every lifecycle task to its CLI command, API call, and Merchant Center screen.

Before you start

You need the following:

The Connect API examples on this page use curl and jq. Get a token once and reuse it:
export CTP_PROJECT_KEY=<project-key>
export CTP_REGION=europe-west1.gcp
export CTP_CLIENT_ID=<client-id>
export CTP_CLIENT_SECRET=<client-secret>
export CONNECT_URL="https://connect.$CTP_REGION.commercetools.com"

TOKEN=$(curl -sS --fail-with-body -u "$CTP_CLIENT_ID:$CTP_CLIENT_SECRET" \
  -X POST "https://auth.$CTP_REGION.commercetools.com/oauth/token" \
  -d "grant_type=client_credentials" | jq -r .access_token)
Use the Connect API host for your Project's Region. Hosts and authorization lists them.

Create a ConnectorStaged

With the Connect CLI

commercetools connect connectorstaged create \
  --repository-url git@github.com:<your-account>/zen-order-confirmation.git \
  --repository-tag v0.2.0 \
  --creator-email you@example.com \
  --name "Zen Electron order confirmation" \
  --key zen-order-confirmation \
  --integration-types email \
  --supported-regions europe-west1.gcp
Set the flags as follows. The CLI reference defines every flag.
  • --key: choose a stable identifier now, because every later command uses it. This is easier than passing IDs around.
  • --integration-types email: classifies the Connector without changing how the Connector runs.
  • --supported-regions: set the Regions you've tested. Leave the flag out to allow every supported Region.

Check the result:

commercetools connect connectorstaged describe --key zen-order-confirmation

With the Connect API

The CLI calls the Create ConnectorStaged endpoint. The endpoint isn't scoped to a Project path; your token's scope decides which Project owns the ConnectorStaged.
curl -sS --fail-with-body -X POST "$CONNECT_URL/connectors/drafts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "zen-order-confirmation",
    "name": "Zen Electron order confirmation",
    "integrationTypes": ["email"],
    "creator": { "email": "you@example.com" },
    "repository": {
      "url": "git@github.com:<your-account>/zen-order-confirmation.git",
      "tag": "v0.2.0"
    },
    "privateProjects": ["europe-west1.gcp:<project-key>"],
    "supportedRegions": ["europe-west1.gcp"]
  }' | jq '{key, version, status, isPreviewable}'
Create ConnectorStaged lists the required fields. This example sets privateProjects, in the format {region}:{projectKey}, so that your Project can deploy the ConnectorStaged for preview and the published private Connector. The CLI's connectorstaged create has no flag for it, so CLI users add Projects with the Add Project to Private Connector update action. The response is a ConnectorStaged with status: "Draft" and isPreviewable: "none". Use one route, not both: the second request fails because the key already exists.
In the Merchant Center, the same step is Create connector. See Create an Organization Connector for the fields.

What the validation pipeline checks

Every preview and publish request runs the validation pipeline against the tag. A private preview or publish skips the Test Connector step and the certification review, because both apply only when you request certification.
The dependency updates you made in Start from the email template are why the SCA step passes here.

Trust the remote report

commercetools connect validate runs the same steps locally, but its SAST can be stricter than the remote gate, so it might report code smells that the remote preview accepts. Use the local run as an early warning. The remote report decides whether you can preview and publish.
Read the remote result in the ConnectorStaged's previewableReport or publishingReport, or on the Connector's Preview Report and Publish Report tabs in the Merchant Center. Check validation status describes both routes. Since 2 July 2026, the Merchant Center reports update in real time as each step runs.
curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{isPreviewable, status, previewable: .previewableReport.entries, publishing: .publishingReport.entries}'
A passing preview report lists Information entries, with titles such as SAST and SCA analysis check succeeded. Entry titles can change, so check each entry's type (ConnectorReportEntryType) rather than matching exact title text.

Preview the ConnectorStaged

A preview Deployment runs the ConnectorStaged's tag in your Project before you publish. The privateProjects list that you set when you created the ConnectorStaged decides which Projects can create it. Preview describes the Deployment type, and Deploy previewable ConnectorStaged states the Project rule.

With the Connect CLI

connectorstaged preview requests previewable status, runs the validations, and creates the preview Deployment in one command. Pass a value for each configuration key in your connect.yaml. The provider call is stubbed, so the provider key and template IDs can be placeholders:
CONFIG=(
  --configuration "mail-sender.CTP_REGION=europe-west1.gcp"
  --configuration "mail-sender.EMAIL_PROVIDER_API_KEY=stub"
  --configuration "mail-sender.SENDER_EMAIL_ADDRESS=orders@example.com"
  --configuration "mail-sender.CUSTOMER_REGISTRATION_TEMPLATE_ID=stub"
  --configuration "mail-sender.CUSTOMER_EMAIL_TOKEN_CREATION_TEMPLATE_ID=stub"
  --configuration "mail-sender.CUSTOMER_PASSWORD_TOKEN_CREATION_TEMPLATE_ID=stub"
  --configuration "mail-sender.ORDER_CONFIRMATION_TEMPLATE_ID=order-confirmation"
  --configuration "mail-sender.ORDER_STATE_CHANGE_TEMPLATE_ID=stub"
  --configuration "mail-sender.ORDER_REFUND_TEMPLATE_ID=stub"
)

commercetools connect connectorstaged preview \
  --key zen-order-confirmation \
  --deployment-key zen-order-confirmation-preview \
  --region europe-west1.gcp \
  "${CONFIG[@]}"
Each value uses the format {applicationName}.{key}={value}, because the keys belong to the mail-sender application. Keep the CONFIG array: the next pages reuse it.

With the Connect API

The API splits the same work into two calls. First, apply the Preview Connector update action with the ConnectorStaged's current version:
VERSION=$(curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" | jq .version)

curl -sS --fail-with-body -X POST "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"version\": $VERSION, \"actions\": [{\"action\": \"updatePreviewable\"}]}" \
  | jq .isPreviewable
While validation runs, isPreviewable is "pending". Monitor Preview status describes the transitions, and IsPreviewable defines the values. Poll the ConnectorStaged until isPreviewable isn't "pending", then read the result:
until [ "$(curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" | jq -r .isPreviewable)" != "pending" ]; do
  sleep 30
done

curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{isPreviewable, report: .previewableReport.entries}'
Continue only if isPreviewable is "true". If it's "false", read the entries with type: "Error" and fix the cause before you request a new preview.
Then create a Deployment that references the ConnectorStaged with staged: true and type: preview. Define the configuration values once as a JSON array. The install and operate pages reuse it, in the same way that the CLI examples reuse CONFIG:
CONFIGURATIONS='[
  {
    "applicationName": "mail-sender",
    "standardConfiguration": [
      { "key": "CTP_REGION", "value": "europe-west1.gcp" }
    ],
    "securedConfiguration": [
      { "key": "EMAIL_PROVIDER_API_KEY", "value": "stub" },
      { "key": "SENDER_EMAIL_ADDRESS", "value": "orders@example.com" },
      { "key": "ORDER_CONFIRMATION_TEMPLATE_ID", "value": "order-confirmation" },
      { "key": "CUSTOMER_REGISTRATION_TEMPLATE_ID", "value": "stub" },
      { "key": "CUSTOMER_EMAIL_TOKEN_CREATION_TEMPLATE_ID", "value": "stub" },
      { "key": "CUSTOMER_PASSWORD_TOKEN_CREATION_TEMPLATE_ID", "value": "stub" },
      { "key": "ORDER_STATE_CHANGE_TEMPLATE_ID", "value": "stub" },
      { "key": "ORDER_REFUND_TEMPLATE_ID", "value": "stub" }
    ]
  }
]'

jq -n --argjson configurations "$CONFIGURATIONS" '{
  key: "zen-order-confirmation-preview",
  type: "preview",
  connector: { key: "zen-order-confirmation", staged: true },
  region: "europe-west1.gcp",
  configurations: $configurations
}' | curl -sS --fail-with-body -X POST "$CONNECT_URL/$CTP_PROJECT_KEY/deployments" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @- | jq '{key, type, status}'
Keep the CONFIGURATIONS variable: the next pages reuse it.
A ConnectorStaged can be deployed only as preview. Environments explains which types need a published Connector.

Test the preview, then delete it

A preview Deployment behaves like any other Deployment, so the checks on Install and test your Connector apply: confirm the Subscription exists, import an Order, and find the stub's log line. Then delete it:
commercetools connect deployment delete --key zen-order-confirmation-preview
The command waits at a y/n confirmation prompt, which can look like a hang in a script.
If provisioning fails, the report might not say why. For example, a preview Deployment with placeholder API Client credentials can fail with no reason in its report. Read the Deployment's logs and recheck its configuration values before you change code. Operate a Deployment covers this.

Every new tag needs a new preview request. A preview Deployment keeps running the tag it was created from.

Publish privately

Publish with certification: false to create a private Connector:
commercetools connect connectorstaged publish --key zen-order-confirmation
The API equivalent is the Publish update action:
VERSION=$(curl -sS --fail-with-body "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" | jq .version)

curl -sS --fail-with-body -X POST "$CONNECT_URL/connectors/drafts/key=zen-order-confirmation" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"version\": $VERSION, \"actions\": [{\"action\": \"publish\", \"certification\": false}]}" \
  | jq '{status, isPreviewable}'
Publishing runs the validation pipeline again, and the Publish action blocks further updates to the ConnectorStaged until the process completes. Poll status until it isn't Processing (ConnectorStatus defines the values), then read publishingReport for the result. To wait for it in a script, reuse the polling loop from the preview step with .status and Processing.
Private publishing and a passing preview report don't run the remote automated tests required for certification. Before installing for real use, test the application behavior separately: the next page verifies an event and a stubbed provider call, not delivery through a real email provider. For Connectors with other application types, test service, event, and job applications locally against their respective contracts.
A private Connector is restricted to the Projects in its privateProjects list. The reliable approach is to list every intended Project, including the creator Project, either in the create request or with the Add Project to Private Connector update action before installation. Project identifiers use {region}:{projectKey}, for example europe-west1.gcp:zen-electron-dev.
With an empty list, only the creator can access the Connector, as ConnectorStagedDraft describes. Don't rely on that for any other Project: add the Project to privateProjects before you install there.

Deleting a ConnectorStaged

The CLI has no delete command for a ConnectorStaged. Delete the Deployments first, then follow Delete ConnectorStaged with the Connect API. Because the request also removes the published Connector, confirm that no Project still needs the Connector before you delete.

Certification, briefly

Certification applies only to public listings on the Connect marketplace. Scope of certification describes the review, and Requirements for certification lists what the repository must contain. Every new tag of a public Connector needs re-certification. Zen Electron's Connector runs only in its own Projects, so Zen Electron's team skips certification.

Production-readiness checklist

The validation pipeline checks that the Connector builds and passes security scans. Private publishing skips remote automated certification tests and doesn't prove that the Connector behaves correctly. The provider call in this module is stubbed, so the preview and install exercises don't prove that a real provider sends email. The commercetools-connect skill's production-readiness checklist covers that gap and gives the full criteria and implementation patterns. The following items are recommended practice, not platform requirements, and are the ones this Connector needs most:
  • Delivery policy: the README records the acknowledgment policy and deduplication for each email type. Implement and test the event app to the contract did this.
  • Message-type and self-change filtering: check the Connector against the skill's Correctness items.
  • Least-privilege scopes and secured secrets: check inheritAs.apiClient.scopes and securedConfiguration against the skill's Security items.
  • Structured logs with correlation keys: log lines carry no Customer data.
  • Repeatable lifecycle scripts: verify the resource after deployment instead of assuming it from the Deployment status.
  • A runbook in the README: cover what happens when the provider is down and how an operator finds missed sends.

Worked example: publish Zen Electron's Connector

  1. Create the ConnectorStaged zen-order-confirmation from tag v0.2.0.
  2. Run connectorstaged preview with the CONFIG array. The preview report passes.
  3. Check the preview Deployment as described on the next page, then delete it.
  4. Publish with certification: false and confirm status: "Published".
Zen Electron now has a private Connector, and the Project that created it can install it. No certification was needed. To install it in another Zen Electron Project, check the privateProjects note in Publish privately first.

Key takeaways

  • A ConnectorStaged is the editable draft that references a repository tag. Publishing it creates the read-only Connector.
  • Every preview and publish request runs the validation pipeline. Automated tests run only for certification.
  • The remote report is the gate. Local connect validate can be stricter, so use it as an early warning.
  • A ConnectorStaged can be deployed only as preview. Delete preview Deployments after testing, and request a new preview for each new tag.
  • Publishing with certification: false creates a private Connector without certification. Certification is only for public listings.
  • Deleting a ConnectorStaged also deletes its published Connector, and the CLI can't do it.

Test your knowledge