Learn how to take payments with a commercetools payment Connector, create Orders at the right moment, reconcile provider webhooks, and refund payments.
This guide covers that template-based direct Connector path: you deploy a payment Connector, wire it into your own storefront, and own the backend around it. On this path the Connector creates and maintains the Payment, and your backend owns three things the template leaves to you:
- the Checkout Session that authenticates the browser to the Connector
- the conversion of the Cart into an Order
- the capture, cancellation, and refund operations that follow the Order
Define the payment requirements
Each decision maps to a configuration value or an architectural choice later in this guide. Document the following before selecting or configuring a Connector:
- Provider and Connector: identify the PSP, the Connector and its version, and whether it is already deployed. Record the processor and enabler URLs if it is.
- Region and Project: the Session, Auth, and API hosts are Region-specific, and a Connector default usually points at one Region.
- Capture mode: decide whether to charge immediately or to authorize now and capture later at fulfillment. Confirm which modes the Connector and provider account support.
- Saved payment methods: decide whether returning shoppers can reuse a stored method. Check the Connector contract for Customer and Cart requirements. Stored methods bind to a Customer, so decide how the Cart carries one; an anonymous Cart stores nothing and the shopper sees no error.
- Partial refunds and split captures: decide whether the business needs partial refunds or multiple captures. Confirm support in both the Connector version and the provider account.
- Payment interface name: decide how the Payment identifies the Connector, so that reconciliation and back-office tooling can select the right Payments.
- Payment methods and layout: list the methods to offer, and choose between a single drop-in element and individual components.
- Billing address collection: decide whether the payment UI collects the billing address or your own checkout does, so that one of the two always supplies the addresses Order creation needs.
- Storefront origins and return URL: list every browser origin that calls the Connector, and the absolute URL the shopper returns to after paying.
- Settlement: determine how the Connector records final payment state and whether your Order gate must wait for a provider webhook.
- Gift cards and store credit: decide whether a gift card Payment Integration will be configured alongside this one, because it changes the Checkout Application configuration.
- Anything else: capture constraints that no fixed list asks about, such as PCI scope, strong customer authentication, purchase-order numbers, subscriptions, marketplace split payments, surcharging, custom fraud scoring, or provider metadata requirements. Record each as its own requirement, because these are the ones most likely to decide whether configuration is enough.
Confirm this list with the business before deriving any configuration. Flag every unusual requirement explicitly, because each one can move the decision in the next section from configure to fork or build.
Choose an integration path
Two decisions happen here, in order. First decide whether commercetools should run the checkout for you. Then, if it should not, decide how much of a Connector you have to build.
Decide between Checkout and a direct Connector integration
Four paths lead to a paid Order, and they differ in who owns the Payment, how payment starts, and which API performs post-purchase operations. Choose one path deliberately.
| Path | Payment owner | Order creator | Post-purchase operations |
|---|---|---|---|
| Checkout in Complete Checkout or Payment Only mode | Checkout | Checkout, while the Transaction is still Pending | Checkout Payment Intents API |
| Checkout Transactions API BETA | Checkout | Checkout payment lifecycle | Checkout APIs |
| Template-based direct Connector integration (this guide) | The Connector processor | Your backend, after the expected Transaction reaches Success | The Connector operation routes |
| PSP integration without a Connector | Your backend | Your backend | Your own provider integration |
paymentFlow and checkoutFlow methods of the Browser SDK, and Checkout creates the Order automatically. Read Payment lifecycle for how Checkout sequences authorization, capture, cancellation, and refund.reversePayment action. The direct Connector path has no equivalent, so on that path you define and operate the same compensation yourself.Choose the template-based direct Connector path, described in the rest of this guide, when you need full control over the checkout experience and over the moment an Order is created, and you accept owning the Session, the Order, and the post-purchase operations.
Choose a Connector path
Check the live Connector landscape at the start of the implementation, and record the Connector key, version, and the date you checked it. Supported providers, payment methods, and capabilities change between Connector versions, so a list written into a document goes stale.
Determine the current state from three sources:
- the supported PSPs, Payment Integration Types, and payment methods table, which lists the Public Connectors that commercetools builds
- the Connect marketplace in the Merchant Center, which also lists Connectors built by providers and other third parties
- the Search Connectors endpoint, which lists published production Connectors. Verify Project access and deployment eligibility separately.
A marketplace listing does not prove that an integration is a deployable Connect Connector. Confirm that a candidate has a Connector definition before treating it as an installable option. If a promising option turns out to be a partner or software-as-a-service integration instead, it falls outside this guide.
Compare each candidate against your requirements on the following dimensions:
- the provider itself
- the payment methods you need
- the integration type, meaning a drop-in element or individual components
- the capture, refund, and stored-method capabilities
- Region and currency coverage
- every unusual requirement you recorded
Then choose the first path that fits:
- Install and configure a Public Connector when its published contract covers the requirements.
- Check whether configuration closes an apparent gap before changing code. Use the selected Connector version and provider account documentation to verify each capability.
- Fork an open-source Connector when the provider has one and configuration genuinely cannot provide the behavior. Add only the missing capability and deploy the result as an Organization Connector. Forking keeps the processor contract, the Session authentication, and the Payment ownership model that already work.
- Build from the payment integration template when no Connector exists for the provider.
connect.yaml, builds the declared applications, and runs security checks.commercetools connect validate
Configure the Connector
Configuration is what makes a Connector behave the way the requirements describe, and most values have a default that decides behavior for you. Set every behavior-changing value deliberately, and record a short reason for each so a wrong assumption is visible.
connect.yaml belongs in the root of the Connector repository, not inside an application folder such as processor or enabler.Configuration that changes payment behavior
| Requirement | What it configures | What to decide |
|---|---|---|
| Capture mode | Automatic or manual capture | Confirm the supported modes and the Transaction that opens your Order gate. |
| Saved payment methods | Stored method support | Confirm the Customer, Cart, and consent requirements. Stored methods bind to a Customer, so confirm the Cart carries one. |
| Partial refunds and split captures | Multiple capture and refund operations | Confirm support in the Connector version and provider account. |
| Payment methods and layout | Available UI integration options | Choose the methods and presentation required by the storefront. |
| Billing address collection | Whether the payment UI collects a billing address | Decide which side collects it, so that the Cart holds every address Order creation requires. |
| Payment interface name | Payment identification | Confirm how the Connector populates paymentMethodInfo.paymentInterface. |
Configuration that fails only at runtime
Validate behavior-changing runtime values before the first test payment. Exact keys and failure responses depend on the Connector version.
- Region hosts: confirm that every configured host matches the Project Region. A host left at a default from another Region fails at authentication or Session creation, not at deployment.
- Return URL: use the URL format required by the Connector contract and test the complete redirect flow. Connectors built from the template parse this value in the browser, so a value without a scheme throws in the enabler and the shopper never returns from the provider.
- Allowed origins: configure the storefront origins required by the Connector and verify browser access. An origin that is missing, or that differs by scheme or port, makes the processor reject the browser with a cross-origin error while the same request succeeds from a server.
- Webhook configuration: follow the Connector and provider requirements for endpoint registration and event verification. Serve the endpoint over HTTPS, and verify the provider signature before the processor changes any state.
API Client scopes
Three separate clients are involved, and conflating them is the usual cause of authorization failures.
- The deployment client authenticates the Connect CLI or the Merchant Center action that creates the deployment. It needs the Connector and deployment scopes. If the Connector generates its own runtime credentials, this client also needs
manage_api_clients:{projectKey}, whichmanage_project:{projectKey}does not include. Without it, deployment fails with an access-denied error. - The Connector runtime client is what the deployed processor uses to call commercetools. Read the Connector definition for its required scopes instead of assuming a fixed list.
- Your own backend client creates Sessions and Orders. It needs at least
manage_sessions:{projectKey}to create a Checkout Session,view_payments:{projectKey}to confirm the Payment succeeded, andmanage_orders:{projectKey}to create the Order.
connect.yaml must not also declare the variables that generation provides, because the duplicate declaration causes a configuration conflict.invalid_scope error at authentication rather than a permission error at the failing call, which sends you looking in the wrong place.manage_project. A broad scope hides which permissions the integration actually needs and does not survive a least-privilege review.Webhook registration after the first deployment
When a Connector requires a deployed processor URL before provider webhook registration, use this sequence:
- Follow the Connector contract for any bootstrap configuration needed for the initial deployment.
- Read the processor URL from the deployment.
- Register the webhook endpoint at the provider and select the events required by the payment flow.
- Update the deployment with the verified webhook configuration.
Select webhook events from the provider and Connector documentation rather than using a fixed list from another integration. Verify each event that moves a Transaction or opens the Order gate. For production, decide separately how to handle the provider's dispute and chargeback events. They arrive long after the Order exists and do not fit the Order gate, so confirm whether the deployed Connector records them on the Payment before assuming a Transaction appears.
Read the processor and enabler URLs from configuration in both your storefront and your backend rather than hardcoding them. A redeploy keeps the URLs of an existing deployment, but a deployment you delete and recreate gets new ones, and every hardcoded copy then points at a dead endpoint.
For an initial deployment, configure every application required by the Connector definition. A redeploy can update a subset of existing application configurations; omitted values remain unchanged.
Implement the payment flow
Your backend, the Connector, and the provider each own part of the flow. The sections below follow one payment from Session creation to refund.
Prove the deployed Connector first
Before wiring the Connector into the storefront, drive it once from a disposable harness: create a Session, load the enabler, submit a provider test card, and confirm the resulting Payment in commercetools. A failed payment looks the same whether the cause is the Connector, its configuration, or your storefront, and this step rules out the first two before the third exists.
A harness can take shortcuts that production must not, such as a throwaway Cart or hardcoded configuration. Keep it out of every deployed environment and discard it once the real flow works.
Create the Checkout Session on your backend
manage_sessions token stay server-side. Return only the Session identifier and the processor and enabler URLs to the browser.Complete these steps in one backend endpoint:
- Verify that the Cart belongs to the caller. Fetch the Cart and compare its
customerIdoranonymousIdagainst the authenticated user before trusting a Cart identifier from the client. - Confirm that the Cart is ready for the selected Connector and payment method. A processor built from the template compares the amount already paid against the Cart total, so a Cart with a zero total is refused as already paid rather than accepted as a free Order.
- Create the Session using the canonical request in Create Checkout Sessions.
- Set the Session metadata required by the deployed Connector contract. When the metadata does not identify the processor the Session is for, the processor rejects an otherwise valid, freshly created Session with a
401reporting that the Session is not active. Check this first when a new Session fails immediately.
The request and response use different Cart paths. Follow the canonical Session representation rather than reusing the request shape in response-handling code.
Create the Session when the shopper reaches the payment step.
sandbox deployments scale to zero when unused and need around 15 seconds to boot again, so the enabler's first call after an idle period can time out. Call the readiness endpoint that the Connector documents immediately after creating the Session and ignore the result; the request only has to wake the processor before the browser needs it. production deployments keep warmed-up instances, so this affects testing rather than live traffic.Render the payment UI
Pass the shopper's locale to the enabler instead of hardcoding one, so that the provider renders its components and its error messages in the language the rest of the storefront uses.
The browser authenticates to the processor with the Session, not with an OAuth token. If you call a processor route directly, send the Session header that the Connector documents; a bearer token does not authenticate you to the processor.
Create the Order after payment
Confirm four preconditions before creating the Order:
- The Cart has a shipping address, which Create Order from Cart requires for every TaxMode. It also carries the Shipping Method and any further addresses your process requires, and
paymentInfo.paymentscontains the Payment that the Connector linked. - The Payment holds the expected
ChargeorAuthorizationTransaction in stateSuccess, and its amount covers the amount your flow requires before Order creation. APendingTransaction has not completed. AFailureTransaction is unrecoverable, but the provider outcome determines whether it represents a shopper decline or another failure. - You are using the current Cart version.
- Your business validations, such as stock and minimum order value, pass.
currentVersion. Fetch the Cart on the server immediately before creating the Order and use the version it returns.orderNumber before the first attempt and reusing it on every retry. After a DuplicateField response, an InvalidOperation error, or an ambiguous 500 Internal Server Error, query the Order by orderNumber. Return the existing Order only when that query finds it; otherwise handle the documented error or retry policy. An InvalidOperation error can have causes unrelated to a previous successful request.Charge Transaction reaches Success. With manual capture, create the Order on a successful Authorization and capture later at fulfillment. Pick one and apply it consistently.On this path the processor creates and maintains the Payment, so your backend must not create Payment objects of its own. A backend that also creates one leaves the Cart referencing more than one Payment for a single attempt, which breaks amount reconciliation and the Order gate that reads the Transaction state.
Open to Confirmed, Complete, or Cancelled; drive those transitions from your fulfillment process, and tie capture and cancellation decisions to the same process. If an OMS or ERP owns that lifecycle, follow the handoff and write-back boundaries in Integrate an order management system.sequenceNumber, monitor Subscription health, and reconcile missed work.Reconcile with the PSP webhook
Success before the provider confirms it.Pending. Reuse the same pre-generated orderNumber across attempts and stop at a defined timeout.Do not make Order creation depend on the shopper keeping the return page open. Consume Payment Transaction state-change Messages, or run a reconciliation job, to retry the same idempotent Order-creation operation on the server. Alert when the server-side retry policy is exhausted.
2xx status code as soon as the event is persisted so the provider does not time out and redeliver. Do any further processing after the acknowledgment.interfaceId links the Payment to the provider record, and Set InterfaceId cannot change the value after it is set. Write it correctly the first time.Capture, cancel, and refund
Keep these operations idempotent using the mechanism defined by the Connector and provider so that a retried capture cannot charge twice.
Provider identifier requirements vary. Confirm which authorization or capture identifier the Connector requires for refunds, and retain the required identifier in your reconciliation data. When a refund passes the authorization identifier to a provider that refunds against the capture, the call fails with a not-found error even though the payment plainly succeeded.
For reconciliation with finance or enterprise resource planning systems, pass your own reference on the operation, and target a specific capture when refunding a Payment that has more than one.
Test the integration
Two suites cover different risks, and the fast one comes first.
Cover the backend decisions with unit tests that mock the outbound boundary, which is the processor, the Sessions API, the commercetools API, and the provider. Assert what your code decided to do, and keep your own orchestration unmocked. These tests need no deployment and no secrets, so they can run on every commit. Cover at least the following:
- Session creation: an owned, payment-ready Cart yields a Session. A Cart belonging to another user yields no Session. A Cart with a zero total yields no Session. The browser response contains the values required by the Connector and no credentials.
- Order creation: an authorized Cart produces exactly one Order and sets
cartStatetoOrdered. APendingorFailureTransaction produces none, and aFailuresurfaces the decline rather than a generic server error. A duplicate-field or invalid-operation response returns an existing Order only after a successfulorderNumberlookup. The Cart version comes from a fresh read. - Post-purchase operations: capture, cancellation, and refund reach the Connector operation routes, and the Checkout Payment Intents API stays untouched. Retrying an operation does not duplicate a successful money movement.
- Webhook handling: a redelivered event changes nothing the second time, provider-required verification runs before any state change, and a verified success event opens the Order-creation gate that was closed.
Then add one full-flow test against a real deployment with provider test cards. Drive it from Session creation through payment, Order creation, capture, and refund, and assert the commercetools state after each step so that a failure identifies which stage failed. Poll for asynchronous settlement rather than sleeping, and skip the test with an explicit message when the deployment configuration is absent, because a silent pass on a missing secret is the same as having no test. Run it after deployments rather than on every commit.
Follow the provider testing documentation when automating payment fields. Use a browser driver when the provider UI requires browser-level interaction. Otherwise, automate up to the mounted payment element or exercise the Order-creation path through a provider-supported test API.
Verify and operate the integration
Verify the complete flow in a non-production Project against a provider test account, using provider test cards rather than real ones.
Pending while asynchronous settlement completes. Use the timing expectations documented for the deployed Connector and provider to distinguish a delayed webhook from a missing one. A completion reported in the browser is not proof of payment because the browser result can precede the commercetools state change.Verify the integration in this order:
- Verify configuration: confirm that the Region hosts, return URL, and allowed origins match the storefront, that the webhook configuration is complete, and that secrets appear only in secured configuration.
- Verify the Session: create a Session from an owned, payment-ready Cart and confirm that the response to the browser contains no credentials. Confirm the processor accepts it.
- Verify the payment: complete a test-card payment. Confirm that
cart.paymentInfo.paymentsreferences the expected Payment attempts, that the selected Payment identifies the Connector as documented, and that successfulChargeorAuthorizationTransactions cover the required amount. Confirm that a single attempt produced a single Payment, because a second Payment for one attempt means something other than the processor created it. Confirm thatinterfaceIdandinterfaceInteractionshold the provider references you need later, because a dispute or a finance query is answered from that record. - Verify the Order: confirm that exactly one Order exists, that
cartStateisOrdered, and that repeating the request with the sameorderNumberreturns the same Order rather than creating another. - Verify settlement: for an asynchronous provider, confirm that the Transaction moves from
PendingtoSuccessafter the webhook, and that Order creation was blocked until it did. - Verify redelivery: replay the same webhook event and confirm that the Payment is unchanged and no second Transaction appears.
- Verify the reverse lifecycle: cancel an authorization before capture and confirm a
CancelAuthorizationTransaction. Then on a separate payment, capture, refund, and confirm theChargeandRefundTransactions with the expected amounts. Include a partial refund if the business needs one. - Verify a decline: pay with a card that the provider declines, and confirm that no Order is created and that the shopper sees the decline rather than a generic error.
Pending beyond the expected webhook delay, webhook verification failures, unhandled dispute and chargeback events, Order-creation retries that exhaust their timeout, and Connector deployment health. Include the Cart identifier, Payment identifier, and provider interaction identifier in structured logs so that a payment can be traced across all three systems.Diagnose common failures
| Symptom | Likely cause | Resolution |
|---|---|---|
| Your code reports that the Session has no Cart reference. | Your code read cart.cartRef.id, which is the request path rather than the response path. | Read activeCart.cartRef.id from the Session response. |
The processor rejects a freshly created Session with a 401 reporting that it is not active. | The Session metadata does not identify the processor the Session was created for. | Set the metadata the deployed Connector contract requires, then create a new Session. |
| The browser cannot reach the processor, but the same request works from a server. | The storefront origin is missing from the allowed origins, or differs by scheme or port. | Add the exact origin to the Connector configuration and redeploy. |
| The shopper pays but never returns to your site. | The configured return URL has no scheme, so the enabler fails to parse it. | Configure an absolute return URL and test the complete redirect. |
| A Cart update fails with a generic processor error. | A stale API Extension registered for Carts points at a dead destination and fires on every Cart update. | Inspect the registered API Extensions and confirm which destination is dead. API Extensions are Project-wide and can belong to another integration, so remove one only after confirming its owner. |
| Order creation fails reporting a different version than expected. | Your backend used a Cart version from the browser, and the processor incremented it when linking the Payment. | Fetch the Cart on the server immediately before creating the Order. |
| Order creation fails reporting that no successful payment was found. | The webhook has not arrived, so the Transaction is still Pending. | Poll and retry on this rejection until the Transaction reaches Success or the timeout expires. |
| A retry fails with an InvalidOperation error. | The first attempt might have succeeded, leaving the Cart in the Ordered CartState, which allows no further operations. The error also has documented causes unrelated to a retry. | Query by the stable orderNumber. Return the Order only when found; otherwise handle the original error. |
The Transaction never leaves Pending. | The asynchronous provider event has not produced the expected state change. | Check the Connector and provider delivery records, then run the reconciliation path. |
The Payment has a Failure Transaction. | The payment operation failed permanently. | Inspect the Connector and provider outcome, show an appropriate shopper message, and do not create the Order. |
| One payment attempt produced two Payments. | Your backend created a Payment that the processor already owns. | Remove the Payment creation from your backend; on this path only the processor creates Payments. |
| A refund fails with a not-found error although the payment succeeded. | The refund used the authorization identifier where the provider refunds against the capture. | Retain the identifier the Connector requires for refunds and pass that one. |
| The first payment after an idle period times out. | The sandbox deployment scaled to zero and is still booting. | Call the Connector's readiness endpoint after creating the Session to warm the processor, or verify against a production deployment. |
| Deployment fails with an access-denied error. | The deployment client is missing a scope, most often manage_api_clients when the Connector generates its own credentials. | Replace the API Client with one that has the complete scope set. |
| Deployment fails reporting a configuration conflict. | The connect.yaml file declares variables that automatic API Client generation also provides. | Remove the generated variables from connect.yaml, or supply the credentials yourself instead of generating them. |
Authentication fails with a 400 invalid_scope error. | The token request names a scope the API Client does not hold. | Request only the granted scopes, or provision a client that holds the required set. |
| Confirming the payment fails with an authorization error after the shopper was charged. | Your backend client lacks view_payments. | Create a new API Client with view_payments and manage_orders, and cover this path in the full-flow test. |
The processor health endpoint returns 401 during a redeploy. | The deployment is still restarting, so the previous container is gone and the new one is not ready. | Wait for the deployment to report as deployed, then retry before investigating authentication. |
| A redeploy does not pick up a new Connector version. | The redeploy kept the current version. | Redeploy with --updateConnector. |