Skip to main content

REST endpoints & webhooks

Evolve services primarily expose a GraphQL subgraph for client consumption. REST endpoints are used for integrations that don't fit the GraphQL model: webhook callbacks from external providers, session management, commercetools API extensions, and payment flows.

When REST, when GraphQL

GraphQL is the API for frontend clients and service-to-service queries through federation. All product, cart, account, and order operations go through GraphQL.

REST is used when:

  • An external system pushes data in (payment webhooks, CMS webhooks)
  • The protocol requires it (commercetools API extensions, OAuth token endpoints)
  • The interaction is a simple request/response without the flexibility needs of GraphQL (session creation, health checks)

Payment webhooks

Each payment provider sends asynchronous status updates through webhook callbacks. Every provider's webhook endpoint follows the same pattern but uses provider-specific verification:

Verification per provider

Method: HMAC

Validates each notificationItem with hmacValidator.validateHMAC() using ADYEN_HMAC_KEY. Returns 202 Accepted on success, 401 on invalid HMAC.

Adyen decouples webhook acknowledgement from processing. The webhook handler publishes each notification to an internal queue and returns 202 immediately. A separate consumer processes notifications and updates commercetools. This prevents Adyen from timing out and retrying when commercetools mutations are slow.

Session endpoints

The account service exposes REST endpoints for session management. These are documented in detail in Authentication & tokens:

  • POST /api/create-session: creates an anonymous session (called by the gateway's @requiresSession directive)
  • POST /token/anonymous: creates an anonymous session with raw token info (used by server-side consumers)
  • POST /api/client-context: returns customer metadata for a given access token (cached in Redis)

commercetools API extensions

commercetools API extensions are synchronous HTTP callbacks that fire when resources are created or updated. They allow services to modify resources during the API call, for example setting defaults on a new cart or generating an order number.

The checkout service registers extensions for:

ResourceActionBehavior
CartCreateCopies customer addresses and email onto the cart. For B2B, uses the business unit's addresses.
CartUpdateAuto-selects a default shipping method when a shipping address is set.
OrderCreateGenerates a unique order number, ensures customer email is set, applies default order type.
PaymentCreateTransitions the payment to the PaymentInitial state.

Extensions are registered through Terraform with a shared secret for authentication:

resource "commercetools_api_extension" "main" {
destination {
type = "HTTP"
url = "${api_gateway_hostname}/${service_name}/extension"
authorization_header = "Bearer ${random_password.api_extension_secret.result}"
}

trigger {
resource_type_id = "cart"
actions = ["Create", "Update"]
}

trigger {
resource_type_id = "order"
actions = ["Create"]
}

trigger {
resource_type_id = "payment"
actions = ["Create"]
}
}

The service validates the Authorization: Bearer <secret> header on every extension request. The handler dispatches based on the resource type and action, then returns update actions or errors:

const handlers = {
cart: {
Create: createCartExtension,
Update: updateCartExtension,
},
order: {
Create: createOrderExtension,
},
payment: {
Create: (payment) => ({
actions: [{ action: "transitionState", state: { typeId: "state", key: "PaymentInitial" } }],
}),
},
};

Because API extensions are synchronous, they add latency to the commercetools API call. Keep extension logic fast and avoid external API calls where possible.