API extensibility overview

Ask about this Page
Copy for LLM
View as Markdown

Overview of the concepts related to extending the functionality of your Composable Commerce Project.

commercetools Composable Commerce provides out-of-the-box data structures and behavior that covers the needs of modern commerce solutions. However, your Project may have unique requirements which require these data structures and behavior to be extended.

Composable Commerce provides a range of API extensibility options, allowing you to customize your Project to accommodate various use cases and to enable further integrations. These customization options are Types, Custom Fields, Custom Objects, API Extensions, Subscriptions, and States.
Learn more about how to use API extensibility options with Composable Commerce in our self-paced Extensibility module.

We've collected a number of common use cases and the recommended extensibility options you can use to achieve them.

Extend resources with Custom Fields

The Types API allows you to define extra fields on supported data types within Composable Commerce. For example, to keep track of loyalty information for a Customer, you could create a Type that defines a field for loyaltyPoints.
When you create a Type on a supported data type, the new fields are not automatically attached to all instances of that data type. Instead, you're creating the possibility to define those values when it makes sense to you. To define the values, use Custom Fields. Custom Fields can only be created using the API.

Every customizable resource can be extended with only one Type at a time. However, a Type can contain any number of different fields. For example, the Customer resource can be extended with only one Type, but this Type could consist of multiple different fields that capture the customer's shoe size, nationality, email preferences, and so on.

For implementation examples, see the Add Custom Fields tutorial.

Extend Project with custom resources

Custom Objects allow you to store namespaced JSON values within your Composable Commerce Project. They are not coupled with any specific resource, and are useful for data accessed infrequently, used by integrations/services, or something you want to represent as an entirely new resource.
For example, if you maintain a list of vendors and suppliers for a specific product, storing this information using Attributes on a Product would mean the whole list is retrieved each time you access the product's data. You can instead use Custom Objects to store this data and only fetch it when necessary.

Similar to Custom Fields, creating Custom Objects is an API-only operation.

Extend API calls

API Extensions are called after the processing of a create or update request of an API call, but before the result is persisted. This makes it useful for synchronous tasks which must be performed before a resource is created or updated.

Good use cases for API Extensions are calculating custom shipping costs or adding mandatory items, like insurance, to a Cart.

API Extension within the flow of the API call

The API Extensions are called during the execution of a create or update request. The system first validates that the requested operation can be done, and applies the operation. However, the created or updated resource is not persisted yet. It is forwarded to the API Extensions, which can run their business logic on it. You can restrict this step to certain use cases with conditional triggers. An API Extension can respond in one of three ways:
  • If the Extension finds the result to be valid, and does not want to perform any changes, it can return a success. The system will persist the result.
  • If the Extension finds that the result is not valid (for example the particular Customer may not purchase this Product), it can return a list of errors. The system will not persist the result and return the errors to the original API Client.
  • If the Extension wants to perform additional changes, it can return a list of update actions (for example if it wants to add mandatory insurance to the Cart, it can return an AddLineItem update). The system will validate that the update actions are valid for the given resource type and will try to perform the updates. Should that fail, the original API Client will receive the errors. Otherwise, the original API Client will receive the final result (for example the Cart including the mandatory insurance).

If an API Extension fails to respond properly

If an API Extension fails to respond properly, the whole API call will fail. If the API Extension did not return a result in time or could not be reached, the original API Client will receive a 504 Gateway Timeout HTTP status code. If the API Extension returns a response, but it could not be parsed properly, the original API Client will receive a 502 Bad Gateway HTTP status code.

In both cases, additional information on the cause of the failure is returned to the original API Client.

In terms of Service Level Agreement (SLA), a failure caused by an API Extension does not count as a failure of the commercetools Composable Commerce API. For example, if an API Extension for the Carts is down and causes downtime for your shop, the SLA won't cover that.

Multiple API Extensions in a single API call

If multiple API Extensions are triggered by an API call, they will be called in parallel. Their responses will be merged, but without a guaranteed order (for example, if two Extensions each return an error, their order in the error list is undefined. If two Extensions return updates, the order in which the updates are performed is undefined).

Responses are merged based on their priority or severity:

  • A failure to respond properly by any API Extension will cause the whole request to fail with a 502 or 504.
  • Otherwise, if any API Extension finds that the result is not valid, the result will not be persisted and an error will be returned to the original API Client.
  • Otherwise, if any API Extension returns updates, the result will be modified before it is returned to the original API Client.

API Extensions should operate on separate concerns. For example for a Cart, it is fine to have an Extension each for validating that a Customer is allowed to purchase age-restricted Products, calculating shipping costs, and adding mandatory insurance. A counter-example is two API Extensions changing the Price of a Line Item: One for adding extra costs for optional gift wrapping, the other reducing the Price if an externally defined Discount applies - If both Extensions want to change the same Line Item, one will overwrite the result of the other. For this use case, the whole Price calculation for Line Items should be performed inside a single Extension.

You also need to find a balance between clean separation and the increasing latency risk when calling many parallel Extensions.

Extension Chaining BETA

When multiple API Extensions are triggered by the same resource and action, they run in parallel by default. If your Extensions depend on each other's results, you can use Extension Chaining to control the order in which they run.

By declaring dependencies on an Extension, you instruct the platform to run the specified Extensions first. A dependent Extension then receives the resource after its prerequisite Extensions' update actions have been applied, so it can build on their results. Extensions without dependencies continue to run concurrently.

Extension Chaining is well suited for checkout flows where order matters. For example, you can apply discounts before tax calculation, or validate addresses before charging a payment.

To declare dependencies, set the dependencies field in the ExtensionDraft when creating an Extension, or use the Set Dependencies update action on an existing Extension. The maximum dependency chain depth is three layers, and each Extension can declare at most five direct dependencies. Circular dependencies are not allowed.

Previous state of the updated resource in API Extensions BETA

By default, the payload sent to an API Extension contains only the resource as it is after the update. If your business logic needs to know what changed, you can configure the Extension to also receive the state of the resource before the update. The Extension can then compare the previous and current states to process only the delta, without external lookups.

To include the previous state, set additionalContext.includeOldResource to true in the ExtensionDraft. The payload then includes an oldResource field alongside resource for Update actions. For Create actions, there is no previous state, so oldResource is not included.
Including the previous state increases the payload size. Be aware of the payload limits of this feature and of your Extension destination (for example, AWS Lambda limits the payload to 6 MB).

Reference Expansion in API Extensions BETA

By default, the payload sent to an API Extension contains only references to related objects, not the full objects themselves. If your business logic requires data from related objects, you can configure expansion paths on an API Extension. The payload then includes the expanded referenced objects, so you don't need to make additional API requests to retrieve them.
For example, if a Cart Extension needs to validate the Customer Group of the Customer on a Cart, you can configure the expansion path customerGroup. The Extension payload then contains the full Customer Group object, not just its reference.
You can configure up to 3 expansion paths per API Extension. To configure expansion paths when creating an API Extension, set the expansionPaths field in the ExtensionDraft. To update the expansion paths on an existing API Extension, use the Set Expansion Paths update action.
Be aware of the limits of this feature and its performance impact. Using Reference Expansion with cloud function destinations, such as Google Cloud Function and AWS Lambda destinations, can increase the payload size and potentially hit payload limits.

Subscribe to notifications

Subscriptions allow you to receive notifications after a resource is modified or an event occurs. Subscriptions are commonly used to trigger asynchronous background processes. For example, by subscribing to the Customer Created and Customer Email Changed Messages, you can implement a system which sends verification emails when these notifications are received.

Composable Commerce provides three notification payload types through Subscriptions:

  • Messages represent changes or actions performed on Project resources, such as Orders, Products, or Customers. They are associated with API queryable resources and include comprehensive metadata such as version and sequenceNumber fields to maintain consistency and ordering.
  • Changes represent updates to a subscribed resource. The payload includes details about whether the resource was created, updated, or deleted.
  • Events represent changes or actions that occur across a broader range of services and use cases. Unlike Messages, Events are not associated with API queryable resources. This design allows Events to support notifications for services beyond the HTTP API, such as Import API, Checkout, and Merchant Center. Events typically contain fewer required fields than Messages, making them simpler and more flexible for diverse notification scenarios.

Use Messages when you need notifications about changes to core Composable Commerce resources. Use Changes when you need a concise payload that indicates whether a resource was created, updated, or deleted. Use Events when you need notifications from services like Import API or for use cases that extend beyond traditional Project resources.

How Subscriptions work

When you create a Subscription with a specific message type and a Destination, Composable Commerce delivers notifications to that Destination whenever the corresponding event occurs. A consumer can then receive the notification and trigger further actions, such as sending an email or updating an external system.
For implementation examples, see the Subscribe to Messages tutorial.

Implement workflows

States allow you to model finite state machines reflecting custom business logic, and are ideal for creating custom workflows. For example, to implement an approval process for new Reviews, you could create the States pending-approval and approved to manage this process.