Extend the behavior of an API with your business logic. An API Extension is called after the processing of a create or update request of an API call, but before the result is persisted. The API Extension can validate the object, or apply a maximum of 100 [additional updates](https://docs.commercetools.com/api/projects/api-extensions#updates-requested) to it. You may host your API Extensions as you wish, but we provide integrations with [serverless functions](https://docs.commercetools.com/api/projects/api-extensions#extensiondestination). You can also deploy API Extensions as `service` applications using [Connect](https://docs.commercetools.com/api/connect/overview#connect-applications). An API Extension affects the performance of the API it is extending. If it fails or takes a second longer to return a result, the whole API call fails or takes a second longer. Use [Subscriptions](https://docs.commercetools.com/api/projects/subscriptions) instead of API Extensions when you can react to events asynchronously. An API Extension is applied to API calls from all clients, including those provided by commercetools, like the Merchant Center. API Extensions are available for the following resources: - [Carts](https://docs.commercetools.com/api/projects/carts) - [Orders](https://docs.commercetools.com/api/projects/orders) - [Payment Methods](https://docs.commercetools.com/api/projects/payment-methods) - [Payments](https://docs.commercetools.com/api/projects/payments) - [Customers](https://docs.commercetools.com/api/projects/customers) - [Customer Groups](https://docs.commercetools.com/api/projects/customerGroups) - [Quote Requests](https://docs.commercetools.com/api/projects/quote-requests) - [Staged Quotes](https://docs.commercetools.com/api/projects/staged-quotes) - [Quotes](https://docs.commercetools.com/api/projects/quotes) - [Business Units](https://docs.commercetools.com/api/projects/business-units) - [Shopping Lists](https://docs.commercetools.com/api/projects/shoppingLists) A Project can have a maximum of 25 API Extensions. When you create, update, or delete API Extensions, it may take up to a minute for the changes to take effect. For more information, see [Eventual Consistency](https://docs.commercetools.com/api/general-concepts#eventual-consistency). This document explains the [creation of an API Extension](https://docs.commercetools.com/api/projects/api-extensions#create-extension), its [input](https://docs.commercetools.com/api/projects/api-extensions#input), [responses](https://docs.commercetools.com/api/projects/api-extensions#response), [conditional triggers](https://docs.commercetools.com/api/projects/api-extensions#conditional-triggers) and [limits and error cases](https://docs.commercetools.com/api/projects/api-extensions#limits-and-error-cases). See the [tutorial](https://docs.commercetools.com/api/tutorials/extensions) on how to set up an API Extension step-by-step based on examples. There, you'll also find information on how to trace requests with correlation IDs. For performance reasons, there are some [time limits](https://docs.commercetools.com/api/projects/api-extensions#time-limits) that are imposed by API Extensions. Follow the [performance tips](https://docs.commercetools.com/api/performance-tips#api-extensions) to maintain a performant user experience. Learn more about using API Extensions in our self-paced Extensibility overview and Integration patterns modules. # Representations ### ExtensionDestination A destination contains the configuration for the Extension, including its `type`, location and authentication details. We believe deploying an API Extension on a Function-as-a-Service is a good practice. Azure Functions can be called with the `HTTP` destination using [AzureFunctionsAuthentication](https://docs.commercetools.com/api/projects/ctp:api:type:AzureFunctionsAuthentication). For Google Cloud Functions, although the `HTTP` destination can be used, we recommend using the dedicated `GoogleCloudFunctionDestination` because invocations can be authorized through the Google Cloud Platform (GCP) Identity and Access Management (IAM). This is simpler than using the `HTTPDestination` and having to provide an authorization token. Secure access to your extension API is also possible via a GCP bridge project. See our [private connectivity](https://docs.commercetools.com/api/private-connectivity#extend-with-other-clouds) guide for details. Secrets or access keys are partially hidden for security when retrieving a destination. #### GoogleCloudFunctionDestination Google Cloud Functions [limit the size of the payload](https://cloud.google.com/functions/quotas#resource_limits). The exact limit is determined by the function's [version](https://cloud.google.com/functions/docs/concepts/version-comparison). commercetools Projects hosted on Google Cloud can benefit from additional security by enabling [Google Cloud's VPC Service Controls](https://cloud.google.com/security/vpc-service-controls). This ensures that Google Cloud Functions can only be accessed from the commercetools Google Cloud infrastructure. To configure VPC Service Controls, specify the commercetools GCP project number as the source of your ingress policy rule. Contact your Customer Success Manager to obtain the required commercetools GCP project number. #### AWSLambdaDestination AWS Lambda limits the [size of the payload to 6 MB](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html#function-configuration-deployment-and-execution). The limit also applies if the Lambda function is invoked by the API Gateway. Do not use AWS Lambda if you anticipate that your API Extension will receive a JSON input exceeding 6 MB. ### HTTPDestinationAuthentication You can secure your HTTP destinations by setting an `Authorization` header using [AuthorizationHeaderAuthentication](https://docs.commercetools.com/api/projects/api-extensions#authorizationheaderauthentication). For calling Azure functions specifically, use [AzureFunctionsAuthentication](https://docs.commercetools.com/api/projects/api-extensions#azurefunctionsauthentication) to specify the function key. #### AzureFunctionsAuthentication ### ExtensionAdditionalContextDraft # Get Extension ## Get Extension by Key # Check if Extension exists ## Check if Extension exists by Query Predicate # Update Extension ## Update Extension by Key # Update actions ### Set Dependencies When you call this action, the following errors can occur: - [400 ExtensionChainTooWide](https://docs.commercetools.com/api/errors#extensionchaintoowide): An Extension declares more than five direct dependencies. - [400 ExtensionChainTooDeep](https://docs.commercetools.com/api/errors#extensionchaintoodeep): The dependency chain exceeds three layers. - [400 CircularDependency](https://docs.commercetools.com/api/errors#circulardependency): A circular dependency is detected. - [400 MissingDependency](https://docs.commercetools.com/api/errors#missingdependency): A referenced Extension does not exist or is not applicable to the same trigger. ### Set Additional Context # Delete Extension ## Delete Extension by Key # Input An `HTTP` Extension will be called via HTTP POST request. An `AWSLambda` Extension will be invoked, and the input is provided as the payload. The object will be persisted as-is if no Extension returns errors or updates. It is therefore identical to the result the user may see, with the exception of timestamps: the `lastModifiedAt` field, and if it is a creation, the `createdAt` field, do not contain the final values. All other fields will be persisted if they are not overridden by an update of an Extension. ## Previous state of the updated resource By default, the Extension payload contains only the resource as it is after the update. If your business logic needs to know what changed, set [`additionalContext.includeOldResource`](https://docs.commercetools.com/api/projects/api-extensions#extensionadditionalcontext) to `true` on the Extension. For `Update` actions, the payload then also includes an `oldResource` field with the state of the resource before the update. The `oldResource` field is not included for `Create` actions. If [expansion paths](https://docs.commercetools.com/api/api-extensibility-overview#reference-expansion-in-api-extensions) are configured, they are applied to both `resource` and `oldResource`. ## Headers For an `HTTP` and a `GoogleCloudFunction` Extension, some headers will be set: - `Content-Type` - `application/json` - `X-Correlation-ID` - A correlation ID can be used to track a request. The same correlation ID will be returned to the original caller of the API. In addition, the `Authorization` or `x-functions-key` header is set if [configured](https://docs.commercetools.com/api/projects/api-extensions#httpdestinationauthentication). For an `AWS Lambda` Extension, the correlation ID information is included in the client context. Find code examples for tracing requests with correlation IDs in the [tutorial](https://docs.commercetools.com/api/tutorials/extensions#tracing-requests-with-correlation-ids). # Response An Extension with an `HTTP` destination must set a proper HTTP status code (`200` or `201` for successful responses, `400` for validation failures). All other status codes will be treated as a failure to respond properly. An Extension with an AWSLambda destination must return without errors (both for successful responses, and validation failures). Throwing an exception in Java, Python, C# or Go, or invoking the callback with an error in NodeJS, will be treated as a failure to respond properly. The response can optionally contain a list of up to 100 [update actions](https://docs.commercetools.com/api/projects/api-extensions#updates-requested) to be applied to the resource. The possible update actions are limited to those available for the resource that triggered the API Extension. This limit can be increased per project after we review the performance impact. For more information, see [API Extensions limits](https://docs.commercetools.com/api/limits#api-extensions). ## Validation successful / No updates requested The body should be completely empty or an empty list of [requested updates](https://docs.commercetools.com/api/projects/api-extensions#updates-requested). An `HTTP` Extension must set a `200` or `201` HTTP status code. ## Validation failed - `errors` - Array of [Error](https://docs.commercetools.com/api/projects/api-extensions#error) - At least one error must be present. An `HTTP` Extension must set a `400` HTTP status code. An `AWSLambda` Extension must add the following field to the JSON: - `responseType` - String - `"FailedValidation"` ### Error - `code` - String Needs to be one of the [defined error codes](https://docs.commercetools.com/api/errors), for example, `InvalidInput` or `InvalidOperation`. - `message` - String User-defined description of the error. - `localizedMessage` - [LocalizedString](https://docs.commercetools.com/api/types#localizedstring) - Optional Localized user-defined description of the error. If a localized message is available for the user's locale settings, the Merchant Center displays it. - `extensionExtraInfo` - JSON Object - Optional Any other information that should be returned to the API caller. For more information, see [errors from Extensions](https://docs.commercetools.com/api/errors#extensions). ## Updates requested - `actions` - Array of update actions for the resourceType. Up to 100 update actions are allowed. For information about increasing this limit, see [API Extensions limits](https://docs.commercetools.com/api/limits#api-extensions). You can use all update actions for the particular resource: - for `cart` you can use any [Cart update action](https://docs.commercetools.com/api/projects/carts#update-actions). - for `order` you can use any [Order update action](https://docs.commercetools.com/api/projects/orders#update-actions). - for `payment-method` you can use any [Payment Method update action](https://docs.commercetools.com/api/projects/payment-methods#update-actions). - for `payment` you can use any [Payment update action](https://docs.commercetools.com/api/projects/payments#update-actions). - for `customer` you can use any [Customer update action](https://docs.commercetools.com/api/projects/customers#update-actions). - for `customer-group` you can use any [Customer Group update action](https://docs.commercetools.com/api/projects/customerGroups#update-actions). - for `quote-request` you can use any [Quote Request update action](https://docs.commercetools.com/api/projects/quote-requests#update-actions). - for `staged-quote` you can use any [Staged Quote update action](https://docs.commercetools.com/api/projects/staged-quotes#update-actions). - for `quote` you can use any [Quote update action](https://docs.commercetools.com/api/projects/quotes#update-actions). - for `business-unit` you can use any [Business Unit update action](https://docs.commercetools.com/api/projects/business-units#update-actions) . - for `shopping-list` you can use any [Shopping List update action](https://docs.commercetools.com/api/projects/shoppingLists#update-actions). An `HTTP` Extension must set a `200` or `201` HTTP status code. An `AWSLambda` Extension must add the following field to the JSON: - `responseType` - String - `"UpdateRequest"` # Conditional triggers By default, API Extensions are always called during an update or create action on the resource they are configured for. However, in certain use cases, the Extension should only be triggered when certain conditions are met. Specifying conditional triggers can eliminate unnecessary API calls to your Extension. This eases the load on your service as well as improves overall performance. You can define conditional statements using the [predicate syntax](https://docs.commercetools.com/api/predicates/query#use-predicates-in-conditional-api-extensions) in the `condition` field of the [ExtensionTrigger](https://docs.commercetools.com/api/projects/api-extensions#extensiontrigger). The condition is evaluated during every create or update action to the configured resource, resulting in one of three outcomes: - The condition evaluates to true and the API Extension is called. - The condition evaluates to false, the API Extension is not called. - The predicate syntax can not be evaluated and the entire API call [fails](https://docs.commercetools.com/api/projects/api-extensions#error-cases). If multiple triggers are defined for the same resource type, the API Extension is invoked if at least one trigger condition evaluates to true. However, if all conditions evaluate to false, the API Extension will not be called. If your predicate contains optional fields, use the `is defined` [operator](https://docs.commercetools.com/api/predicates/query#on-standard-and-custom-fields) to ensure that the field exists and has a non-null value. This will ensure that a missing field will not cause the evaluation of the condition to fail. For further examples and use-cases, follow our [tutorial](https://docs.commercetools.com/api/tutorials/extensions) on API Extensions. # Extension Chaining By default, when multiple API Extensions are configured for the same resource and action, the platform triggers them concurrently. This ensures the lowest possible latency for your API requests. However, if your business logic requires a specific execution order, you must configure Extension Chaining by declaring dependencies. For example, if you want to calculate taxes only after calculating discounts, one API Extension needs to calculate a value based on the output of another. ## Declare dependencies When you declare dependencies between API Extensions, you transition from a parallel execution model to a sequential flow. The following example shows how to declare a dependency on another API Extension in the `dependencies` field of the Extension: ```json title="Example API Extension with dependency to one other API Extension" highlightLines="17" { "id": "extension-id", "key": "extension-key", "destination": { "type": "HTTP", "url": "https://example.com/api-extension" }, "triggers": [ { "resourceTypeId": "cart", "actions": ["Create", "Update"] } ], "dependencies": [ { "typeId": "extension", "id": "id-of-extension-this-depends-on" } ] } ``` An API Extension with a dependency enters a waiting state. It only executes once each declared ancestor Extension has completed successfully. If you declare dependencies to more than one Extension, like in the example below, the Extension will wait for all of them to complete before it executes: ```json title="Example API Extension with dependency to multiple API Extensions" highlightLines="17,21" { "id": "extension-id", "key": "extension-key", "destination": { "type": "HTTP", "url": "https://example.com/api-extension" }, "triggers": [ { "resourceTypeId": "cart", "actions": ["Create", "Update"] } ], "dependencies": [ { "typeId": "extension", "id": "id-of-extension-this-depends-on-1" }, { "typeId": "extension", "id": "id-of-extension-this-depends-on-2" } ] } ``` In this case, the Extension receives the resource updated by applying all update actions received from the ancestor Extensions. ## Diamond dependency example The following example of a diamond dependency graph illustrates a more complex scenario with multiple dependencies. Consider four API Extensions: - A has no dependencies, - B and C both depend on A, and - D depends on both B and C. ```mermaid title="Example of a diamond dependency graph with four API Extensions" graph TD A --> B A --> C B --> D C --> D ``` The API Extensions are executed in the following order: - A runs first and completes successfully. - B and C run concurrently after A completes and both receive the resource after A's update actions. - D waits for B and C, then receives the resource after A, B, and C update actions are applied. After all Extensions have completed, the API applies all collected update actions together and persists the result. ```mermaid title="Execution order of API Extensions in a diamond dependency graph" sequenceDiagram autonumber participant Platform as commercetools API participant ExtA as Extension A participant ExtB as Extension B participant ExtC as Extension C participant ExtD as Extension D Note over Platform: Triggers multiple Extensions activate Platform Platform->>ExtA: Run (No dependencies) activate ExtA note right of ExtA: Processes, no updates ExtA-->>Platform: Return success (Continue) deactivate ExtA Note over Platform: ExtA complete. Dependencies for B and C met. par Run concurrently Platform->>ExtB: activate ExtB and Platform->>ExtC: activate ExtC end note right of ExtB: Processes, adds update actions ExtB-->>Platform: Return success (Updates) deactivate ExtB note right of ExtC: Processes, adds update actions ExtC-->>Platform: Return success (Updates) deactivate ExtC Note over Platform: ExtB and ExtC complete.
Dependencies for D met. Platform->>ExtD: Run (Depends on B and C) activate ExtD note right of ExtD: Receives resource with
updates from B and C.
Adds more actions. ExtD-->>Platform: Return success (Updates) deactivate ExtD Note over Platform: All extensions complete. Platform->>Platform: Apply collected update actions
to resource. deactivate Platform ``` ## Performance considerations Chained Extensions add sequential latency. To minimize the latency impact, design your dependency graph to be as wide and as shallow as possible. The platform enforces the following constraints on Extension Chaining to ensure performant execution of API Extensions: - Maximum direct dependencies per Extension: 5 - Maximum chain depth (layers): 3 - Circular dependencies: Not allowed These constraints are validated when you create or update an API Extension and at request time. If a declared dependency does not exist or does not apply to the same trigger and action as the current request, the platform returns a `MissingDependencyError`. The platform enforces a 60-second limit for API requests. Ensure the cumulative execution time of your extension chain does not exceed this limit. You can configure specific timeouts for each Extension as described in the [time limits](https://docs.commercetools.com/api/projects/api-extensions#time-limits) section. ## Summary With Extension Chaining, the platform ensures that API Extensions are executed in the correct order based on their dependencies, and that each Extension receives the resource state updated by its dependencies. - Extensions without dependencies start immediately and run concurrently. - An Extension with dependencies waits until all declared dependencies have completed and applied their update actions. # Limits and error cases An API Extension affects the performance and uptime of the API it is extending. Therefore, you should carefully consider the technology used to implement the API Extension and your hosting options. We believe that deploying an Extension on a Function-as-a-Service is a good fit. You should get a very high up-time and auto-scaling at low costs. However, you should optimize your functions for good cold-start performance. Independently of the technology choice, you should make sure that the network latency between the [Region](https://docs.commercetools.com/api/general-concepts#regions) your Project is running on and your extension is as low as possible. ## Time limits Because API Extensions are synchronous, any latency in the Extension response directly increases the total response time of the API request. To ensure platform stability, the following timeout limits apply: - Connection limit: The timeframe in which the commercetools API must establish a connection with the API Extension on your infrastructure is 1 second. - Response limit: The timeframe in which an API Extension must return a result is 2 seconds by default (including network latency), but is configurable. The default response limit is a good starting point for your performance evaluations. [Configure a timeout](https://docs.commercetools.com/api/projects/api-extensions#set-timeoutinms) that is optimal for your specific use case and the expected latency of your API Extension. For example, if your API Extension performs complex calculations or calls third-party APIs, you might need a longer timeout for the API call to succeed. If your API Extension performs simple validations, you should set a timeout below the 2-second default. A good target is to respond within 50 ms to fail fast and avoid blocking the platform API call for too long. You can [configure a custom timeout](https://docs.commercetools.com/api/projects/api-extensions#set-timeoutinms) per Extension up to a maximum of 10 seconds. If your API Extension requires a timeout longer than 10 seconds, a per-Project increase can be requested and is subject to a performance review. To request an increase, contact the [commercetools support team](https://support.commercetools.com) with your Region, Project key, and use case. For best practices on keeping API Extensions fast, see [API Extensions performance tips](https://docs.commercetools.com/api/performance-tips#api-extensions). ## Error cases In any error case (such as no response within the time limit or a bad response like a `500` HTTP status code) the API call fails. The API Extension is not retried within an API call, but further API calls will try to reach the API Extension again. The following errors codes are returned when an API Extension does not respond successfully: - [400 ExtensionPredicateEvaluationFailed](https://docs.commercetools.com/api/errors#extensionpredicateevaluationfailed) - [502 ExtensionBadResponse](https://docs.commercetools.com/api/errors#extensionbadresponse) - [502 ExtensionUpdateActionsFailed](https://docs.commercetools.com/api/errors#extensionupdateactionsfailed) - [504 ExtensionNoResponse](https://docs.commercetools.com/api/errors#extensionnoresponse) The following errors are returned when [Extension chaining](https://docs.commercetools.com/api/projects/api-extensions#extension-chaining) constraints are violated on create, update, or at request time: - [400 ExtensionChainTooWide](https://docs.commercetools.com/api/errors#extensionchaintoowide): An Extension declares more than five direct dependencies. - [400 ExtensionChainTooDeep](https://docs.commercetools.com/api/errors#extensionchaintoodeep): The dependency chain exceeds three layers. - [400 CircularDependency](https://docs.commercetools.com/api/errors#circulardependency): A circular reference is detected among the dependencies. - [400 MissingDependency](https://docs.commercetools.com/api/errors#missingdependency): A referenced Extension does not exist or is not applicable to the same trigger. When you delete an Extension, the following error is returned if other Extensions depend on it: - [400 ExtensionDependencyExists](https://docs.commercetools.com/api/errors#extensiondependencyexists): An Extension cannot be deleted because other Extensions depend on it.