# Integrate a payment service provider Learn how to take payments with a commercetools payment Connector, create Orders at the right moment, reconcile provider webhooks, and refund payments. Learn more about integrations in the self-paced [Integration patterns](/learning-integrate-with-commercetools/integration-patterns/overview.md) module. This guide assumes the selected Connector follows the [payment integration template](/connect/templates/payment-integration.md). In that model, the Connector records the payment service provider (PSP) outcome in a [Payment](/search.md?urn=ctp:api:type:Payment), and your backend coordinates the surrounding checkout and Order workflow. For the Payment data model, see [Payments](/api/projects/payments.md). 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 Before continuing, obtain a commercetools Project, access to [Connect](/connect), a PSP test account, and a backend you control. Building a Connector from scratch, and the certification lifecycle for one, are out of scope. This guide links to them where the decision arises. ## 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](/checkout) in Complete Checkout or Payment Only mode | Checkout | Checkout, while the Transaction is still `Pending` | [Checkout Payment Intents API](/checkout/payment-intents-api.md) | | [Checkout Transactions API](/checkout/transactions-api.md) | 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 | Choose Checkout when you want commercetools to run the payment step or the whole checkout, and you accept its Order-creation timing. [Payment Only mode](/checkout/overview.md#payment-only-mode) replaces only the payment step and leaves your address and shipping screens alone, while [Complete Checkout mode](/checkout/overview.md#complete-checkout-mode) replaces the whole checkout page. You start each mode with the `paymentFlow` and `checkoutFlow` methods of the [Browser SDK](/checkout/browser-sdk.md), and Checkout creates the Order automatically. Read [Payment lifecycle](/checkout/payments-lifecycle.md) for how Checkout sequences authorization, capture, cancellation, and refund. Checkout also offers [Automated Reversals](/checkout/payment-integration-predicates.md#automated-reversal-predicates) , which cancel or refund a Payment automatically when Order creation fails, as long as the Connectors in your Project support the `reversePayment` action. The direct Connector path has no equivalent, so on that path you define and operate the same compensation yourself. Choose the Checkout Transactions API when Checkout should manage the payment lifecycle without rendering the Checkout UI. This option is useful for server-driven flows such as recurring payments. Gift cards are a separate Connector contract that only Checkout drives. If shoppers will pay with a gift card or store credit, see [Integrate a gift card system](/guides/gift-card-integration.md). A gift card Payment Integration should always be configured alongside the payment integration described here, because a gift card balance often does not cover the whole Cart. 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 PSP integration without a Connector only when no Connector suits the provider and you want your backend to create the Payment itself. That model is covered in [Payment](/learning-implement-checkout/custom-checkout/payment.md), and it is the one case where your own code creates Payment objects. The [Checkout Payment Intents API](/checkout/payment-intents-api.md) works only for Payments that Checkout created. On the direct Connector path it cannot capture or refund your Payments, however similar the request looks. ### 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](/checkout/connectors-and-applications.md#supported-psps-payment-integration-types-and-payment-methods) table, which lists the Public Connectors that commercetools builds - the Connect marketplace in the [Merchant Center](/merchant-center/connect.md), which also lists Connectors built by providers and other third parties - the [Search Connectors endpoint](/connect/connectors.md#search-connectors), 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: 1. **Install and configure a Public Connector** when its published contract covers the requirements. 2. **Check whether configuration closes an apparent gap** before changing code. Use the selected Connector version and provider account documentation to verify each capability. 3. **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. 4. **Build from the [payment integration template](/connect/templates/payment-integration.md)** when no Connector exists for the provider. The last two options put you on the Connector build path in [Connect](/connect), and this guide resumes once the Connector is deployed. Two consequences of that path are worth knowing before you choose it. First, Connect application templates are for development purposes and require further customization before you use them in a production Project. The payment integration template mocks a payment method using primary account number data, so replace that with the tokenization and encryption the provider offers before you accept real payments. Build to the [best practices](/connect/templates/payment-integration.md#best-practices) the template documents, which cover idempotency, fault tolerance, PCI compliance, webhook verification, duplicate handling, acknowledgment speed, and retry policy. Second, before publishing a Connector, run the documented [validation pipeline](/connect/validation-pipeline.md) locally. Connect runs the same class of checks whenever you request a preview build or publish a Connector, so a local run turns a late rejection into an early fix. The pipeline validates `connect.yaml`, builds the declared applications, and runs security checks. ```bash title="Validate the Connector" commercetools connect validate ``` ## Configure the Connector A Connector built from the [payment integration template](/connect/templates/payment-integration.md) separates browser-facing and provider-facing responsibilities between an enabler and a processor. 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. Key names differ between Connectors and versions. Read the deployed Connector definition with the [Connect API](/connect/connectors.md) rather than copying a key list from another implementation. For a custom Connector, follow [Configure connect.yaml](/connect/development.md#configure-connectyaml); the validation pipeline checks the file against the Connector specification schema. `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}`, which `manage_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, and `manage_orders:{projectKey}` to create the Order. The deployment client must satisfy the requirements for the Connector credential model. See [Automatically generate API Client credentials](/connect/modify-connector.md) for the required scope and configuration constraints. When a Connector generates its own credentials, its `connect.yaml` must not also declare the variables that generation provides, because the duplicate declaration causes a configuration conflict. Request only scopes that the API Client actually holds. A token request that names a scope the client lacks returns a [400 `invalid_scope` error](/learning-developer-essentials/authentication-authorization/scopes.md) at authentication rather than a permission error at the failing call, which sends you looking in the wrong place. Provision the backend client with the complete scope set before testing payments because [API Client scopes are immutable after creation](/api/projects/api-clients.md#create-api-client). Test the Payment read and Order creation before accepting shopper traffic. Grant specific scopes rather than `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: 1. Follow the Connector contract for any bootstrap configuration needed for the initial deployment. 2. Read the processor URL from the deployment. 3. Register the webhook endpoint at the provider and select the events required by the payment flow. 4. 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. After a [redeploy](/connect/deployments.md#redeploy), verify the effective configuration and Connector version. If you recreate the deployment, verify the application URLs and update the provider webhook registration when an endpoint changes. 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 A [Checkout Session](/checkout/installing-checkout.md#create-checkout-sessions) is what authenticates the browser to the processor. Create it on your backend, never in the browser, so that client credentials and the `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: 1. Verify that the Cart belongs to the caller. Fetch the Cart and compare its `customerId` or `anonymousId` against the authenticated user before trusting a Cart identifier from the client. 2. 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. 3. Create the Session using the canonical request in [Create Checkout Sessions](/checkout/installing-checkout.md#create-checkout-sessions). 4. 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 `401` reporting 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](/connect/deployment-behavior-and-environments.md#environments), 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 Integrate the enabler using the bundle format, initialization sequence, readiness event, and authentication mechanism documented for the deployed Connector version. The enabler renders the provider's own payment components, which keeps card data inside the provider and [reduces your PCI compliance obligations](/connect/templates/payment-integration.md#enabler-application). Determine your own required compliance level rather than assuming the Connector removes the obligation. 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. Enable the **pay** button only after the documented readiness condition is met, because the payment element mounts before the provider's frame can accept input. Confirm when the provider payment intent is created so that abandoned browser sessions do not create unnecessary provider records. 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 Converting the Cart into an Order is your responsibility when the selected Connector follows the [payment integration template](/connect/templates/payment-integration.md), which excludes cart-to-order conversion. Verify this responsibility in the contract of any other Connector. ```mermaid title="Immediate capture with synchronous settlement" sequenceDiagram autonumber participant Storefront participant Backend participant Platform as commercetools box commercetools Connect participant Processor end participant PSP as Payment service provider Storefront->>Backend: Request a payment Session Backend->>Platform: Verify Cart ownership and total Backend->>Platform: Create the Checkout Session Platform-->>Backend: Return the Session Backend-->>Storefront: Return the Session and Connector URLs Storefront->>Processor: Submit the payment Processor->>PSP: Charge the shopper PSP-->>Processor: Confirm the charge Processor->>Platform: Create the Payment with a Charge Transaction Processor->>Platform: Link the Payment to the Cart Processor-->>Storefront: Report completion Storefront->>Backend: Request Order creation Backend->>Platform: Fetch the current Cart and Payment Backend->>Platform: Create the Order Platform-->>Backend: Return the Order ``` Confirm four preconditions before creating the Order: 1. The Cart has a shipping address, which [Create Order from Cart](/api/projects/orders.md#create-order-from-cart) requires for every [TaxMode](/search.md?urn=ctp:api:type:TaxMode). It also carries the Shipping Method and any further addresses your process requires, and `paymentInfo.payments` contains the Payment that the Connector linked. 2. The Payment holds the expected `Charge` or `Authorization` Transaction in state `Success`, and its amount covers the amount your flow requires before Order creation. A `Pending` Transaction has not completed. A `Failure` Transaction is unrecoverable, but the provider outcome determines whether it represents a shopper decline or another failure. 3. You are using the current Cart version. 4. Your business validations, such as stock and minimum order value, pass. Never use a Cart version supplied by the browser. The [payment integration template](/connect/templates/payment-integration.md) contract has the processor link the Payment to the Cart during payment submission, which increments the Cart version after the browser captured it. Passing the stale value produces a [ConcurrentModification](/search.md?urn=ctp:api:type:ConcurrentModificationError) error, which reports the expected and actual versions and returns `currentVersion`. Fetch the Cart on the server immediately before creating the Order and use the version it returns. Make Order creation idempotent by generating a unique `orderNumber` before the first attempt and reusing it on every retry. After a [DuplicateField](/search.md?urn=ctp:api:type:DuplicateFieldError) response, an [InvalidOperation](/search.md?urn=ctp:api:type:InvalidOperationError) 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. Order creation timing follows the capture mode. With immediate capture, create the Order once the `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. If the Cart total changed between authorization and Order creation, because a Discount expired or a Price moved, do not proceed silently. Order creation rejects these changes with [PriceChanged](/search.md?urn=ctp:api:type:PriceChangedError), [DiscountCodeNonApplicable](/search.md?urn=ctp:api:type:DiscountCodeNonApplicableError), [MatchingPriceNotFound](/search.md?urn=ctp:api:type:MatchingPriceNotFoundError), [OutOfStock](/search.md?urn=ctp:api:type:OutOfStockError), and [ShippingMethodDoesNotMatchCart](/search.md?urn=ctp:api:type:ShippingMethodDoesNotMatchCartError) errors, each of which arrives after the shopper has already paid. Cancel the authorization and re-authorize for the new amount, or present the new total for confirmation. For the ways a Cart can change during payment and how to detect them, see [Payment](/learning-implement-checkout/custom-checkout/payment.md). Define compensation for an unrecoverable Order-creation failure after payment succeeds. Cancel a successful authorization or refund a successful charge according to the Connector and provider contracts, then record the outcome for reconciliation. Checkout automates this step with [Automated Reversals](/checkout/payment-integration-predicates.md#automated-reversal-predicates) ; on the direct Connector path it is your code that has to run it. 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. After the Order exists, moving it through [OrderState](/search.md?urn=ctp:api:type:OrderState) is your responsibility. Neither the Connector nor Checkout advances an Order from `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](/guides/oms-integration.md). Keep work that follows the Order out of the request path. An [OrderCreatedMessage](/search.md?urn=ctp:api:type:OrderCreatedMessage) delivered through a [Subscription](/api/projects/subscriptions.md) can trigger confirmation emails and downstream synchronization. For the email flow, see [Integrate email](/guides/connect-email-integration.md). [Subscriptions deliver at least once, with no ordering or delivery-time guarantee, and stop after the retry window for the destination](/api/projects/subscriptions.md#delivery-guarantees). Make consumers idempotent, process `sequenceNumber`, monitor Subscription health, and reconcile missed work. ### Reconcile with the PSP webhook When the provider settles asynchronously, the authoritative payment state is the commercetools Payment as updated by the provider webhook that the processor verifies. A success reported in the browser is provisional. Never mark a Transaction `Success` before the provider confirms it. ```mermaid title="Authorization with asynchronous settlement and later capture" sequenceDiagram autonumber participant Storefront participant Backend participant Platform as commercetools box commercetools Connect participant Processor end participant PSP as Payment service provider Storefront->>Processor: Submit the payment Processor->>PSP: Authorize the payment Processor->>Platform: Create the Payment with a Pending Authorization Processor->>Platform: Link the Payment to the Cart Processor-->>Storefront: Report completion Storefront->>Backend: Request Order creation Backend->>Platform: Read the linked Payment Backend-->>Storefront: Refuse while the Transaction is Pending PSP-->>Processor: Deliver the authorization event Processor->>Platform: Set the Authorization Transaction to Success Storefront->>Backend: Retry Order creation Backend->>Platform: Fetch the current Cart and Payment Backend->>Platform: Create the Order Platform-->>Backend: Return the Order Backend->>Processor: Capture at fulfillment Processor->>PSP: Capture the funds Processor->>Platform: Add a Charge Transaction ``` The browser can return before asynchronous settlement completes. For the shopper experience, poll the backend when the expected Transaction is still `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. Make webhook handling idempotent so a redelivered event leaves the Payment unchanged and does not add a second Transaction. Apply the event-verification mechanism required by the provider before changing state, and acknowledge with a `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. The `interfaceId` links the Payment to the provider record, and [Set InterfaceId](/search.md?urn=ctp:api:type:PaymentSetInterfaceIdAction) cannot change the value after it is set. Write it correctly the first time. ### Capture, cancel, and refund Post-purchase money movements happen after the Order exists and belong to your back-office or fulfillment backend, not the storefront. The [payment integration template](/connect/templates/payment-integration.md) defines processor operations for capture, refund, and cancellation. Use the authentication, authorization, request shape, and idempotency contract documented by the deployed Connector version. The hosted [Checkout Payment Intents API](/checkout/payment-intents-api.md) acts only on Payments created by Checkout and cannot serve the direct Connector path. The processor records operation outcomes with the standard [Transaction types](/search.md?urn=ctp:api:type:TransactionType). See [Payment lifecycle](/checkout/payments-lifecycle.md) for capture, authorization cancellation, and refund semantics. 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. A Connect [service application request times out after five minutes](/connect/deployment-behavior-and-environments.md#service). Design provider operations and recovery so that an ambiguous timeout can be reconciled without repeating a successful money movement. Retry outgoing provider requests with an exponential backoff policy rather than an immediate loop, and log the Cart, Payment, and provider interaction identifiers with each attempt. ### 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 `cartState` to `Ordered`. A `Pending` or `Failure` Transaction produces none, and a `Failure` surfaces the decline rather than a generic server error. A duplicate-field or invalid-operation response returns an existing Order only after a successful `orderNumber` lookup. 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. A Transaction can stay `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: 1. **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. 2. **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. 3. **Verify the payment**: complete a test-card payment. Confirm that `cart.paymentInfo.payments` references the expected Payment attempts, that the selected Payment identifies the Connector as documented, and that successful `Charge` or `Authorization` Transactions 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 that `interfaceId` and `interfaceInteractions` hold the provider references you need later, because a dispute or a finance query is answered from that record. 4. **Verify the Order**: confirm that exactly one Order exists, that `cartState` is `Ordered`, and that repeating the request with the same `orderNumber` returns the same Order rather than creating another. 5. **Verify settlement**: for an asynchronous provider, confirm that the Transaction moves from `Pending` to `Success` after the webhook, and that Order creation was blocked until it did. 6. **Verify redelivery**: replay the same webhook event and confirm that the Payment is unchanged and no second Transaction appears. 7. **Verify the reverse lifecycle**: cancel an authorization before capture and confirm a `CancelAuthorization` Transaction. Then on a separate payment, capture, refund, and confirm the `Charge` and `Refund` Transactions with the expected amounts. Include a partial refund if the business needs one. 8. **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. Once live, monitor Transactions that stay `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](/api/projects/api-extensions.md) 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](/search.md?urn=ctp:api:type:InvalidOperationError) error. | The first attempt might have succeeded, leaving the Cart in the `Ordered` [CartState](/search.md?urn=ctp:api:type: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`. | ## Related pages - [Area overview page with navigation](/guides.md) - [Previous page: Integrate external tax](/guides/tax-integration.md) - [Next page: Integrate gift cards](/guides/gift-card-integration.md) - [Search documentation and API specs](/search.md)