Build, test, deploy, install, and certify production-ready commercetools Connect applications — service/API-extension, event/subscription, job, and merchant-center custom apps — in TypeScript, JavaScript, or Java, and integrate a deployed connector into a custom storefront. Covers the connect.yaml contract, least-privilege scopes, lifecycle scripts, sync-vs-async idempotency/ack, testing, and deployment. Includes connector sub-areas for payment (Stripe, Adyen, PayPal), tax (Avalara, Vertex, TaxJar), PIM (Akeneo), CRM (Salesforce, HubSpot), order-management/OMS, gift cards, transactional email (SendGrid, Mailgun), marketplace (Mirakl), promotion and loyalty (Talon.One, Voucherify), analytics export to a warehouse/CDP (BigQuery, Snowflake, Segment), and search/product discovery (Algolia). Use when building, configuring, forking, or debugging a commercetools Connect connector, or syncing commercetools data to or from an external system. Not for the hosted Checkout widget (see commercetools-checkout).
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Build, test, deploy, install, and certify production-ready commercetools Connect applications — service/API-extension, event/subscription, job, and merchant-center custom apps — in TypeScript, JavaScript, or Java, and integrate a deployed connector into a custom storefront. Covers the connect.yaml contract, least-privilege scopes, lifecycle scripts, sync-vs-async idempotency/ack, testing, and deployment. Includes connector sub-areas for payment (Stripe, Adyen, PayPal), tax (Avalara, Vertex, TaxJar), PIM (Akeneo), CRM (Salesforce, HubSpot), order-management/OMS, gift cards, transactional email (SendGrid, Mailgun), marketplace (Mirakl), promotion and loyalty (Talon.One, Voucherify), analytics export to a warehouse/CDP (BigQuery, Snowflake, Segment), and search/product discovery (Algolia). Use when building, configuring, forking, or debugging a commercetools Connect connector, or syncing commercetools data to or from an external system. Not for the hosted Checkout widget (see commercetools-checkout).
when_to_use
["Building a Connect application or connector — a service/API-extension, event/subscription, job, or merchant-center custom application — and fixing the sync-vs-async contract before coding","Writing or debugging connect.yaml, standardConfiguration/securedConfiguration, inheritAs scopes, or post-deploy/pre-undeploy lifecycle scripts that register extensions, subscriptions, or custom types","Deploying, installing, redeploying, or certifying a connector; choosing a region or deployment type","Syncing commercetools to or from an external system (ERP, WMS, OMS, tax, email, search, CRM, data warehouse/CDP)","Payment connectors for a custom storefront (Stripe, Adyen, Mollie, PayPal, ...): integrate a deployed one, fork, or build from the payment-integration template — session BFF, Order after authorization, capture/refund/cancel, webhook reconciliation; debugging the round trip (Session-is-not-active 401, transaction stuck Pending, refund on the wrong API, missing Order)","Tax connectors (Avalara, Vertex, TaxJar): configure/fork or build the calculator API Extension + order-syncer Subscription from the tax-integration template; debugging taxedPrice missing, a 202 response, or transactions absent from the tax dashboard","PIM/product-catalog sync (e.g. Akeneo): use/fork/build; mapping families/attributes/locales/categories onto Product Types; Import API vs HTTP API, event-webhook vs job","CRM connectors (Salesforce, HubSpot, Dynamics 365, Zoho): use/fork/build; direction + source of truth; linking by externalId; migration vs delta sync; debugging duplicate contacts or an infinite sync loop","Order-management/OMS connectors (fulfillmenttools, Fluent Commerce, kbrw, OneStock, NewStore, Pipe17): install/fork/build; order export on OrderCreated, status/shipment/fulfillment inbound webhook, inventory sync","Gift-card connectors (Voucherify, in-house store credit): use/fork or build from the gift-card-integration template; enabler UI + processor (balance/redeem, Payment Intents refund/reverse); debugging checkout stuck on a short balance or redeem double-charging","Transactional-email connectors (SendGrid, Mailgun, AWS SES, Postmark): configure/fork or build the one event app from the transactional email template; at-most-once vs at-least-once + dedupe; debugging no emails (Subscription not registered), duplicates, or silent drops","Marketplace connectors (Marketplacer, Mirakl, Convictional, channel managers): operator vs selling on an external marketplace, role + direction per domain; modeling sellers/offers (Channels/Stores, per-seller prices/inventory, one Product per shared SKU, syncInfo); debugging duplicate Products or channel-less prices","Promotion/loyalty connectors (Talon.One, Voucherify, Dovetech, Eagle Eye): rule out native discounts first, then use/fork/build the evaluator API Extension + redemption Subscription (setDirectDiscounts); debugging inert Discount Codes or double redemption","Analytics export to a data warehouse/CDP/product-analytics tool (BigQuery, Snowflake, Segment): no turnkey connector and no Export API, so build an event streamer on Subscriptions/Messages plus a batch job (lastModifiedAt windowing + cursor pagination) from the product-export template, deduped on the destination side; debugging duplicate rows or missing events; distinct from Platform Insights (APM) and Change History (governance)","Search/product-discovery connectors (Algolia, Constructor, Bloomreach, Elasticsearch, Typesense): rule out native Product Search first, then use/fork or build from the product-export template the two outbound apps (full-ingestion service/job + incremental-updater event on ProductPublished/ProductUnpublished), staged=false projection, atomic reindex; debugging ghost records, a half-empty rebuild, or wrong price/locale in results","Implementing a spec/plan/tasks.md task annotated [SKILL: commercetools-connect]","An implementation-plan step that builds a Connect app, API Extension, Subscription, or MC custom app"]
Intent-driven guidance for building production-ready Connect applications. This skill teaches the decision frameworks, platform contracts, and best practices that survive a production-readiness review — not a single connector's code. It generalizes patterns (and warns against anti-patterns) found in real connectors, and grounds every platform fact in official docs.
Language scope: Connect applications can be written in JavaScript/TypeScript or Java (docs); the create-connect-app template supports JS and TS. This skill targets TypeScript/Node — the decision frameworks, platform contracts (timeouts, ack semantics, scopes, lifecycle), and connect.yaml guidance are language-agnostic and apply equally to a Java connector, but the code snippets and the supertest + msw test stack are Node/Express-specific.
Tooling — use the Connect CLI, don't hand-roll. Scaffold, run, and ship with the official Connect CLI (@commercetools/cli). Every CLI command, the bootstrap flow, and the pinned dependency versions live in one place: the Connect CLI reference (connect-cli.md). Merchant Center custom applications/views are the exception: they use a separate frontend toolchain (@commercetools-frontend/*) and only ride the Connect CLI at deploy time and directory structure — see merchant-center-cli.md and merchant-center-customizations.md.
Workflow
When this skill is invoked, always follow these steps:
Docs search (required, run first) — Always begin by searching docs for this skill. This is the mandatory grounding step: it gathers the latest verified documentation as context for you (the agent). Do not skip it, and do not replace it with another tool (such as an MCP documentation-search tool) This script optimizes for tuned search results — run this command:
Use its output as your primary grounding. You may additionally use the commercetools Knowledge MCP or https://docs.commercetools.com/connect for deeper follow-up.
Route with the decision framework (below) — Pick the application type and lock in the sync-vs-async contract before writing code. The contract determines almost every later decision.
Open the matching reference(s) in ./references/ and build to their patterns and ## Checklist.
Gate on the production-readiness checklist (below) before declaring the connector done.
Optional scripts
Fetch GraphQL schema — Run this when you need context about a commercetools GraphQL query or mutation — for example, to inspect a resource's fields, types, and available operations before writing a query, or to verify a GraphQL query/mutation you have just generated against the real schema. It fetches the partial GraphQL SDL for a single commercetools resource:
The output is the GraphQL SDL for that resource. If the resource name is not recognized, the script prints the list of valid resource names — pick the correct one and re-run. Note: the SDL may contain stubbed types — referenced resources rendered as stubs, with their real type name given in a comment. Fetch any you need separately by re-running this script with that type name as --resource-name.
Fetch OpenAPI (REST) schema — Run this when you need context about a commercetools REST endpoint, request/response payload, or update action — for example, to inspect a resource's REST operations before constructing a request, or to verify a REST request/payload you have just generated against the real specification. It fetches the partial OpenAPI specification for a single commercetools resource:
The output is the OpenAPI specification (YAML) for that resource. REST resources use a read/write-split naming form (e.g. api-Cart-read, api-Cart-write). If the resource name is not recognized, the script prints the list of valid resource names — pick the correct one and re-run. Note: the spec does not include reference-expansion schemas — fetch a referenced resource's schema separately by re-running this script with that resource as --resource-name.
Step 1 — Decision framework: which application type?
A Connector is one repository declaring one or more applications in connect.yaml. Pick each application's type by how your code is invoked and which way data flows, not by what it does.
Two things to fix first:
Direction. Is commercetools the source of the change (commercetools → external system), or is the external system the source (external system → commercetools)? Both are common; they route differently.
service is just an HTTP endpoint, not necessarily an API Extension. A service app exposes an HTTP endpoint. That endpoint can be registered as an API Extension (commercetools calls it synchronously inside an operation) or be a plain inbound webhook / REST API that an external system calls to push data in. These are two modes with different contracts.
Trigger / need
Type
How your code is invoked
Hard contract
Block or modify a commercetools operation before it persists (validate a cart, inject tax, reject an order)
service as API Extension
commercetools calls your endpoint synchronously during the API request (registered as an Extension)
Extension response limit: 2 s default, 10 s self-service max (per-project increases available via support request, subject to performance review). Your latency and downtime become the platform's.
An external system pushes data into commercetools as it changes (system A updates a product → upsert it into commercetools)
service as inbound webhook / API
the external system calls your endpoint
5-min service request timeout. You authenticate the caller and call the commercetools API yourself; no Extension is registered.
React to a commercetools change after it happened (sync a confirmed order to a WMS, send an email, index a product)
event (Subscription handler)
commercetools delivers a Subscription message to a queue → your handler
At-least-once, no ordering, redelivery on non-ack. Must be idempotent.
Scheduled or on-demand batch (nightly poll an external system and upsert, reconcile, cleanup, bulk import)
job
a cron scheduler (properties.schedule)
Request times out after 30 min. No concurrency guard — you own locking.
A single connector commonly combines types (e.g. a service API Extension that calculates tax on the cart plus an event handler that commits the transaction when the order is placed; or a service inbound webhook for live pushes plus a job for nightly full reconciliation).
The build-side guidance in this skill is connector-type-agnostic (any service/event/job). Some connector types also have a focused, end-to-end sub-area that owns the whole job for that type — from "is there a connector already?" through configuring, forking, or building one, to the application backend around it:
The full payment lifecycle for a custom storefront: decide whether a certified/public connector fits → configure it, or fork it, or spin up a new one from the payment-integration template → build the backend (session BFF, Order after authorization, capture/refund/cancel via the processor, webhook reconciliation); plus debugging the round trip
The full tax integration: decide whether a certified connector fits (Avalara/Vertex have them; TaxJar does not) → configure it, fork it, or build from the tax-integration template → the two apps (a cart API Extension that calculates tax in ExternalAmount mode + an OrderCreated Subscription that records/commits the transaction); plus the sandbox-doesn't-persist and no-nexus-means-zero traps
The full customer-relationship integration: decide whether a public connector fits (classic CRMs usually have none → build) → configure it, fork it, or build for a CRM you define → pick direction + source of truth first, then the customer-sync apps it implies (event syncers out, an inbound webhook/poll in, a one-time migration job), all linked by externalId; plus the duplicate-contact, sync-loop, and PII/deletion traps
The full product-data sync job: decide whether a public PIM connector fits → configure it, or fork it, or build one → map the PIM model onto Product Types/attributes/categories/media, keep price & inventory separate, and pick the sync architecture (Import API vs HTTP API, event webhook vs job)
Order management (OMS, e.g Fluent Commerce, kbrw, OneStock, NewStore, Pipe17)
Connect commercetools to an OMS: decide whether to install a public connector → configure it, or fork/customize one, or build a new one for a bespoke order-management service (scaffold from the fulfilment-integration template) → design the sync (order export on OrderCreated, status/shipment/fulfillment inbound webhook, inventory sync, reconcile job). No fixed connector contract; composes the type-agnostic event/service/job build-side
Gift card (e.g Voucherify, in-house store credit, ...etc)
The full gift card integration: decide whether to use a public connector directly (Voucherify), customize/fork one, or build a new one from the gift-card template for a gift card system you define → the two apps (an enabler UI + a processor that checks balance, redeems value, and owns the Payment via session-authenticated balance/redeem and Payment Intents refund/reverse); plus the must-pair-with-a-fallback and sample-only-simulates traps
The full transactional email integration: decide whether a ready-made connector fits (email is template-first — most ESPs have none) → configure it, fork/customize it, or build the one event app from the transactional email template → the app (a Subscription on Customer/Order Messages → send via the ESP); the central at-most-once vs at-least-once decision for a non-idempotent send; plus the token-email, order-state-filtering, and localization traps
Marketplace — multi-vendor, or selling on an external marketplace (e.g Marketplacer, Mirakl, Convictional, channel managers, ...etc)
The full marketplace integration: fix the role (operator vs selling on someone else's marketplace) and direction per domain → ask the user whether to use a public connector directly, customise/fork one, or build for a service they define (most marketplace listings are partner integrations, and there is no marketplace template) → model sellers and offers (Channel/Store/CustomObject per seller, per-seller prices + inventory, one Product for a shared SKU) → build the sync apps (seller + offer sync, order import or per-seller routing with syncInfo, fulfilment status, reconciliation); plus the channel-less-price, aggregated-availability, and un-deletable-Channel traps
The full promotion integration: first rule out native Cart Discounts/Discount Codes/Discount Groups (rung 0) → then ask the user whether to use a public connector as-is, customise/fork one, or build one for a promotion service they define (there is no promotion template) → the two apps (a cart API Extension that applies the engine's discounts via setDirectDiscounts + an OrderCreated Subscription that redeems and awards points); plus the Direct-Discounts-make-Discount-Codes-inert rule and the double-redemption and abandoned-cart traps
Analytics — export to a data warehouse / CDP / product-analytics tool (e.g BigQuery, Snowflake, Redshift, Databricks, Segment, mParticle, ...etc)
The full analytics egress: there is no turnkey analytics connector and no Export API, so (after the live registry check) build from the product-export template → a directional egress pipeline of two primitives, an event streamer on Subscriptions/Messages (near-real-time) and/or a job querying the API with lastModifiedAt windowing + cursor pagination (batch/backfill) → the event→row transform and destination-side dedup on resource.id+sequenceNumber; plus the disambiguation from Platform Insights (APM) and Change History (governance), the client-side-tracking boundary, and the duplicate-row/missing-event/payloadNotIncluded traps
The full search integration (outbound, backend-only — no API Extension): first rule out native Product Search / Product Projection Search (rung 0) → then use a public connector, fork one, or scaffold from the product-export template → map a Product Projection onto a flat search document (price-context, locales, category denormalization, Store assortment) → the two apps (a full-ingestion service/job that atomically reindexes the catalog + an incremental-updater event on ProductPublished/ProductUnpublished/store-selection Subscriptions); plus the ghost-record, half-empty-rebuild, and eventual-consistency traps, and the vendor-hosted-integration-is-not-a-connector rule
Start at the matching overview.md for any payment-, tax-, CRM-, PIM-, order-management-, gift-card-, email-, marketplace-, promotion-, analytics-, or search-connector task — integrating a deployed one or building/forking one. Each decision ladder routes you: rung 1 configure, rung 2 config-closes-the-gap, rung 3 fork, rung 4 build-from-template (provider gotchas live in the provider file — payment/stripe.md, tax/avalara.md, email/providers.md; the CRM and PIM sub-areas are vendor-neutral — look the connector up live; the OMS sub-area has no fixed connector contract and composes the build-side directly; the gift-card sub-area has one public connector (Voucherify) plus a build-from-template path for an in-house system; the marketplace sub-area is vendor-neutral and has no template — assess any fork candidate from its current repo; the promotion sub-area has two public MIT integrations and no template — promotion/public-connectors.md names which artifact is actually the production one; the analytics sub-area has no turnkey connector and no Export API — it still forces a live registry check, then builds a directional egress pipeline from the product-export template — analytics/destinations.md routes the warehouse/CDP/product-analytics/BI decision; the search sub-area is vendor-neutral, gates on native Product Search first, and scaffolds the outbound build from the product-export template). It hands back to the build-side workflow and references above only for the deep, type-agnostic publish/certify lifecycle and the production-readiness gate.
The promotion and search sub-areas each have a rung 0. commercetools ships its own discount engine (Cart Discounts, Discount Codes, Discount Groups) and its own search (Product Search / Product Projection Search), so "should this be a connector at all?" is a real question in those two in a way it isn't for payment, tax, or the rest — rule the native capability out explicitly before recommending a connector.
Each sub-area lives under references/integrations/<type>/ with its own overview.md. Adding another connector type later (e.g. shipping) means adding a sibling references/integrations/<type>/ tree and one row here — the build-side guidance does not change.
Marketplace listings are not all Connect connectors — verify before recommending
Whenever a sub-area has you check the commercetools marketplace for an existing connector, apply this rule regardless of connector type or vendor:
The marketplace is fine as a discovery source, but it lists integrations that are not necessarily commercetools Connect connectors — partner-operated services, SaaS products, and iPaaS middleware appear alongside deployable Connect applications. It can also be out of sync with the actual Connect connector registry (a listing may exist for something not deployable via Connect, or the version may differ), and any specific vendor (Akeneo, Stripe, …) may or may not be listed at any given time — never assume a named connector exists.
Double-check that a candidate is actually a commercetools Connect connector before recommending it as install/configure/fork: look for a Connect affordance (a public connector repo / connect.yaml / a Connect deploy action), and treat the Connect CLI / connector registry as authoritative over the marketing listing.
Then ask the user what to do — don't silently pick. Present the fit and whether it's Connect-deployable.
If the user wants to use a non–Connect integration, warn that this skill does not cover using non–Connect connectors — its build/configure/deploy patterns (connect.yaml, the Connect CLI, lifecycle scripts, the Connect deployment model) don't apply. Point them to the vendor/partner's own onboarding, and offer the in-skill alternative: build or fork a Connect connector instead.
Open every sub-area with the paths — don't wait to be asked
When a request routes into any sub-area above, the user has told you what they want to integrate. They have not told you how, and it is not yours to assume. So before requirements gathering, before config, before code — lay out the paths and let the user pick one:
Native first, where a rung 0 exists (promotion, search). If commercetools already ships the capability, say so plainly and stop. Don't design around something the platform does.
Deploy an existing public connector as-is — grounded in a live registry/marketplace check, never memory, and verified Connect-deployable per the rule above.
Fork and modify an existing connector — when there's a real gap that configuration can't close.
Build a new one — from the sub-area's template, or from the type-agnostic service/event/job patterns when no template exists.
State which rung you'd recommend and why, then ask the user to choose. These are materially different amounts of work and the decision is theirs, not yours.
Do this unprompted, in your first substantive response in the sub-area — including (especially) when the user's phrasing already sounds like it presumes an answer. "Build me an X integration", "sync Y into commercetools", or naming a service they're already running are not instructions to skip the ladder: a user who says "build" usually means "make this work" and will happily take an install if one exists. Ask a clarifying question or two first if you genuinely can't fit-check without it, but don't let requirements gathering delay the landscape — present what exists early, then let the requirements decide the rung.
Each sub-area's overview.md carries the full ordered gate (its Step 1.4/1.5) with the fit criteria and the template to build from. This is the rule that governs all of them.
Step 2 — Price the contract before you build
The expensive mistakes come from not pricing the contract you just chose:
service as API Extension couples your availability and latency to the commercetools operation. A slow or down extension makes carts and orders slow or impossible. So: a tight outbound timeout under the extension timeout, a deliberate fail-open vs. fail-closed decision, and minimizing work on the hot path (skip redundant external calls).
service as inbound webhook is not coupled to a commercetools operation (the 5-min service timeout applies, not the 2 s extension limit), but you own everything: authenticate the caller, validate the payload, and make the write idempotent (the same product update may arrive twice) — upsert by key, don't blind-create. Decide what a failed write returns so the caller can retry safely.
Asynchronous (event) trades immediacy for resilience but hands you at-least-once delivery, no ordering, and redelivery. So: idempotency keyed on a stable identifier, redelivery-safe acks (2xx for "don't send again"), re-fetch the resource by ID rather than trusting a possibly-stale or omitted payload, and self-change filtering to avoid loops.
job owns its own scheduling headroom, overlap locking, and restart-safe checkpointing; each unit of work must be idempotent so a re-run or overlap can't double-write.
If you cannot articulate, in one sentence each, your latency budget (extension), your idempotency strategy (inbound webhook / event / job), and your fail/retry behavior, you are not ready to write the handler.
Production-readiness checklist (the gate)
A connector is not done until every applicable item holds. Each maps to a reference with the implementation pattern.
Reliability
Idempotency strategy stated and implemented — statelessly. Reprocessing a message is a no-op via the target system's own idempotency, re-fetching the commercetools resource and re-checking its state, or upsert by a stable key — never a local dedup store. → event-applications.md
Redelivery-safe responses. Event endpoints return a positive ack (102/200/201/202/204) for handled and irrelevant-but-acked messages; anything other than 102, 200, 201, 202, or 204 triggers a retry. → event-applications.md
Re-fetch by ID, don't trust the payload. Handlers fetch the current resource by resource.id; required when payloadNotIncluded is set. → event-applications.md
Hot-path work minimized (sync). Extensions skip the external call when relevant data is unchanged (e.g. a stored hash) and short-circuit early. → service-applications.md
Security
Inbound endpoints authenticated. Service extensions register a destination whose authentication.type is the discriminator value AuthorizationHeader — not the schema's type name AuthorizationHeaderAuthentication, which fails with InvalidJsonInput — (or AzureFunctions) and validate that secret in-app. Webhooks from external systems validate a full JWT (signature, issuer, audience, subject, expiry, algorithm). A postDeploy that hits this typo may not surface as a failed deployment, so confirm the Extension actually registered via GET /{projectKey}/extensions. → security.md, service-applications.md Pattern 1
Least-privilege CT scopes. Use inheritAs.apiClient.scopes with only the scopes the apps need (e.g. manage_orders, manage_subscriptions, manage_extensions) — not an admin/manage_project client. → security.md
Secrets in securedConfiguration. API keys, client secrets, JWT secrets are never standardConfiguration and never hardcoded. → security.md
No stack traces or secrets in responses. Error middleware returns a generic message in production. → security.md
Correctness
Envelope validation. Envelope decoded per the injected destination type — branch on CONNECT_SUBSCRIPTION_DESTINATION (Pub/Sub: message.data is base64; SNS has its own envelope) — then validated (→ JSON → resource ref → notificationType) before any processing; malformed envelopes rejected. → event-applications.md
Message-type filtering. Subscribe to only the needed message types; ack-and-ignore anything else (including the platform's test/subscription messages). → event-applications.md
Self-change filtering. Updates your own connector makes don't re-trigger it into a loop. → event-applications.md
Route path matches connect.yamlendpoint. The Express router is mounted at the same base path as the app's endpoint (e.g. endpoint: /service ↔ app.use('/service', router)), or the platform's traffic 404s. → project-structure.md
Pinned SDK + client versions. JS/TS: @commercetools/platform-sdk@^8 + @commercetools/ts-client@^4 (not the legacy @commercetools/sdk-client-v2). Java: spring-boot-starter-parent 3.5.15+ and commercetools Java SDK 19+. Typed end to end, no any escapes, mapped at the boundary. → connect-cli.md (Step 3).
Observability
Structured logs with correlation IDs. JSON logs carry the message/resource correlation key (X-Correlation-ID for extensions, resource.id + sequenceNumber for events) on every log line for a request. → observability-operations.md
Idempotent lifecycle scripts.postDeploy creates resources get-then-update (create only if absent), never blind delete-then-recreate. preUndeploy cleans them up. → lifecycle-scripts.md
Deploy-time dependency validation.postDeploy test-connects to external services and surfaces invalid credentials immediately. → lifecycle-scripts.md
Fail-open vs fail-closed documented. The README states, per use case, what happens when the external dependency is down, and outbound calls have a timeout budget. → service-applications.md
Poison-message / replay runbook. How a repeatedly-failing message is handled (DLQ / dropped after retention) and how to replay. → observability-operations.md
Quality
Tests cover the real behavior, run via commercetools connect application test. At minimum: the parameterized auth-rejection matrix (missing/expired/wrong-issuer/wrong-audience/alg:none), envelope/ack edge cases (event) or the pure business logic + response actions (service), an idempotency/duplicate-delivery test, and idempotent postDeploy registration. A couple of happy-path tests is not enough. → testing.md
No dead code, no any escapes. No commented-out blocks; SDK types preserved end to end. → project-structure.md
Scaffolded and run with the Connect CLI. Project created via commercetools connect init; commercetools connect validate passes. → connect-cli.md (Step 2)
Generated connector docs
The connector ships a README stating its fail-open/fail-closed stance, required scopes, a configuration table (every connect.yaml key), and the poison-message/replay runbook. → deployment-installation.md
Custom application vs custom view; config-file contract; develop/test locally; deploy via Connect (connect.yaml merchant-center-* types, order of operations)
Integrating a deployed payment connector (sub-area)
Start at the overview; it routes to the rest (integrate, configure, fork, or build a new one). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the backend-focused workflow: requirements → is-a-certified-connector-enough → config → BFF/Order/capture-refund/webhook
Integrating or building a tax connector (sub-area)
Start at the overview; it routes to the rest (configure a certified connector, fork one, or build both apps from the template). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the two-app workflow: requirements → is-a-certified-connector-enough → config → calculate + record
The two-app contract: the calculator API Extension (all four tax actions, 200-not-202, fail modes, call reduction) + the order-syncer Subscription (commit/void/refund, idempotency); full pitfall catalog
Avalara ground truth (from the certified open-source connector): exact keys, AvaTax createTransaction quote-vs-commit, tax-code/entity-use mapping, MC config app — plus TaxJar as the build-from-template contrast
Integrating or building a CRM connector (sub-area)
Start at the overview; it routes to the rest (configure a public connector, fork one, or build for a CRM you define). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the sync workflow: requirements → direction + source of truth → is-a-public-connector-enough → config → build the sync apps
Requirements → connect.yaml: direction → app composition, source of truth, externalId/Custom-Field linking, least-privilege scopes, secured config; worked example
Start at the overview; it routes to the rest (use a public connector, configure, fork, or build one). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the sync-focused workflow: requirements → is a public connector enough? → configure/fork/build → data mapping → verify
Build or fork a connector: Import API vs HTTP API, service webhook vs job, full vs incremental, idempotent upsert, dependency resolution, delete handling
Testing & safely running a sync: mapping unit tests, then a bounded sandbox-only live run with a pre-flight item count, large-catalog gate, and idempotency re-run (never production credentials)
Start at the overview; it routes to the rest (use a public connector, customize/fork one, or build a new one for a bespoke OMS) and applies the sync design to all paths. See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — direction & source of truth, the requirements → use/configure/fork/build ladder, and the export/inbound/reconcile workflow
Build a new connector for a user-defined OMS (rung 4): scaffold, which applications to declare, connecting to the OMS API, what to reuse from templates
OMS connectors have no fixed runtime contract, so the build side composes the type-agnostic event/service/job references above (scaffolding from the fulfilment-integration CLI template); deploy uses deployment-installation.md, not a sub-area-specific flow.
Integrating or building a gift card connector (sub-area)
Start at the overview; it routes to the rest (use a public connector directly, customize/fork one, or build a new one from the gift-card template). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the two-app workflow: requirements → use/customize/build → config → balance + redeem + refund
Integrating or building an email connector (sub-area)
Start at the overview; it routes to the rest (configure a ready-made connector, fork/customize one, or build the one event app from the transactional email template). See also the Connector-type integration sub-areas section above. This is a pure event app, so it builds on event-applications.md.
Concern
Reference
Start here — the one-app workflow: requirements → is-a-ready-made-connector-enough → config → send + verify
Requirements → connect.yaml: which Messages, ESP key + per-email template IDs, sender, least-privilege scopes scoped to the emails in use; worked example
The one-app contract: Subscription registration + message→email routing, the at-most-once vs at-least-once decision for a non-idempotent send, the token-email (≤60 min) gotcha, order-state filtering, localization, PII; full pitfall catalog
Integrating or building a marketplace connector (sub-area)
Start at the overview; it routes to the rest (use a public connector directly, customise/fork one, or build for a marketplace service the user defines). See also the Connector-type integration sub-areas section above. Marketplace listings especially often aren't Connect connectors — apply Marketplace listings are not all Connect connectors before recommending one.
Concern
Reference
Start here — the workflow: disambiguate "marketplace" → role + direction per domain → which path → seller/offer modeling → build the sync apps
Which path — ask the user: use a public connector as-is, customise/fork, or build for their service; live listing check, and how to assess a fork candidate from its current repo (connect.yaml, handlers, mapping) against the production gate
Seller + offer modeling and connect.yaml: Channel/Store/CustomObject per seller, offer keying, per-seller price/stock scoping, Order Import + syncInfo, the Project limits that constrain the design, scopes; worked example
Verify the round trip: seller usable, offer sellable per seller, order imported/routed exactly once, multi-seller split; the channel-less-price, aggregated-availability, throttling, and un-deletable-Channel traps
Integrating or building a promotion / loyalty connector (sub-area)
Start at the overview; it routes to the rest (rule out native discounts first, then use a public connector, customise/fork one, or build one for your own engine). See also the Connector-type integration sub-areas section above.
Concern
Reference
Start here — the workflow: requirements → native-or-connector → use/customise/build → config → evaluate + redeem
Native, use, customise, or build? the rung-0 native check (Cart Discounts/Discount Codes/Discount Groups), the live-marketplace procedure, the per-engine landscape, and why there is no promotion template
Requirements → connect.yaml: how discounts land on the cart (setDirectDiscounts vs negative custom line items vs engine-managed codes), coupon-code custom field, scopes; worked example
The two-app contract: the evaluator (effect→action mapping, permyriad, coupon rejection without failing the cart, 200-not-202, fail-open, call reduction, extension chaining with tax) + the redemption-syncer (redeem/rollback, idempotency, session identity); full pitfall catalog
Which public integration to actually use — Talon.One's Connect connector is a third party's while the vendor's own repo is a PoC accelerator; Voucherify's is a port, not an install — plus the commercetools-side fixes to apply when forking
Verify the round trip: directDiscounts on the cart, redemption in the engine; the inert-discount-codes, zero-discount, fail-open-self-heal and cart-merge traps
Integrating or building an analytics connector (sub-area)
Start at the overview; it routes to the rest (run the live registry check, then build a directional egress pipeline from the product-export template). See also the Connector-type integration sub-areas section above. There is no turnkey analytics connector and no Export API, so this composes the type-agnostic event/job build-side (event-applications.md, job-applications.md).
Concern
Reference
Start here — the egress workflow: requirements → is-a-connector-enough (live check anyway) → pipeline design → build test-first; disambiguates commerce analytics from Platform Insights + Change History; draws the client-side boundary
Is a connector enough? the forced live registry/marketplace check even though build is expected; how a CDP/ELT loader changes the answer; the configure/fork/build-from-product-export-template ladder
Destinations: warehouse vs CDP vs product-analytics vs BI — stream-vs-batch, what data flows, PII implication; the Subscription brokers; the client-side-first honesty caveat for GA4/Mixpanel
Verify the round trip: one change → one row (no duplicate), batch window loads idempotently; the no-subscription / duplicate-row / payloadNotIncluded / query-off-by-default traps
Integrating or building a search connector (sub-area)
Start at the overview; it routes to the rest (rule out native Product Search first, then use a public connector, fork one, or scaffold from the product-export template for your engine). It is outbound and backend-only — no API Extension. See also the Connector-type integration sub-areas section above. An engine's own dashboard-configured integration (e.g. "Algolia for commercetools") often isn't a Connect connector — apply Marketplace listings are not all Connect connectors before recommending one.
Concern
Reference
Start here — the workflow: rung-0 native gate → requirements → use/fork/build → data mapping → the two apps → verify
Native, use, fork, or build? the rung-0 native-search gate (Product Search / Product Projection Search), the live-marketplace check, the vendor-hosted-integration trap, and scaffolding from the product-export template
Requirements → the search document + connect.yaml: the two apps (full ingestion + incremental updater), index/engine keys, read-only least-privilege scopes, secured config; worked example
Data mapping (the heart): Product Projection → flat document, objectID keying, record granularity, the price-context explosion, localization, category denormalization, Store assortment, the availability boundary
Related skills: SDK client setup, scopes, query predicates, and core data model live in commercetools-platform — link to it rather than restating client/auth basics here. Tax modes (Platform/External/ExternalAmount/Disabled), discount stacking order, sortOrder semantics, and Direct-Discounts-blocking-Discount-Codes as domain concepts are in commercetools-commerce-patterns; these sub-areas cover the connectors that drive them.