Разработка кастомных API Extensions для commercetools

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка кастомных API Extensions для commercetools
Сложная
~5 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка кастомных API Extensions для commercetools

API Extensions — механизм синхронных хуков в commercetools. При определённых операциях с ресурсами платформа делает HTTP-запрос к вашему сервису до или после сохранения, ожидая ответ в течение 2 секунд. Это единственный способ добавить бизнес-логику прямо в lifecycle ресурсов без форка платформы.

Типы триггеров

Trigger Ресурс Когда срабатывает
Create Cart, Order, Customer, Payment При POST
Update Cart, Order, Customer, Payment При POST /ID
Delete Customer, Shopping List При DELETE /ID

Наиболее востребованные: Cart-Update (пересчёт цен, валидация промокодов), Order-Create (отправка в ERP), Payment-Update (синхронизация статусов оплаты).

Регистрация Extension

const extension = await apiRoot.extensions().post({
  body: {
    key: "cart-validation-extension",
    destination: {
      type: "HTTP",
      url: "https://extensions.your-service.com/cart-validate",
      authentication: {
        type: "AuthorizationHeader",
        headerValue: `Bearer ${process.env.EXTENSION_SECRET}`,
      },
    },
    triggers: [
      {
        resourceTypeId: "cart",
        actions: ["Create", "Update"],
      },
    ],
    timeoutInMs: 2000,
  },
}).execute();

Extension с типом AWSLambda или GoogleCloudFunction вызывается напрямую без HTTP — платформа подписывает запрос через IAM.

Структура Extension сервиса

// extensions/src/cart-handler.ts
import express from "express";
import { ExtensionInput, CartUpdateAction } from "@commercetools/platform-sdk";

const app = express();
app.use(express.json());

app.post("/cart-validate", async (req, res) => {
  const input: ExtensionInput = req.body;
  const { action, resource } = input;
  const cart = resource.obj; // полный объект корзины

  const actions: CartUpdateAction[] = [];
  const errors: ExtensionError[] = [];

  // Пример: минимальная сумма заказа
  if (action === "Update" && cart.totalPrice.centAmount < 50000) {
    errors.push({
      code: "InvalidInput",
      message: "Минимальная сумма заказа — 500 ₽",
      extensionExtraInfo: { field: "totalPrice" },
    });
  }

  // Пример: автоматически применить скидку для VIP
  if (cart.customerGroup?.id === "vip-group-id") {
    const alreadyHasVipDiscount = cart.discountCodes?.some(
      (dc) => dc.discountCode.id === "vip-discount-id"
    );
    if (!alreadyHasVipDiscount) {
      actions.push({
        action: "addDiscountCode",
        code: "VIP10",
      });
    }
  }

  if (errors.length > 0) {
    return res.status(400).json({ errors });
  }

  res.json({ actions });
});

Ответ с actions — commercetools применит их атомарно к ресурсу. Ответ с errors — операция отклонится, клиент получит 400.

Extension для пересчёта цен

Сценарий: цены берутся из внешней ERP, не из commercetools Price.

app.post("/cart-reprice", async (req, res) => {
  const { resource } = req.body as ExtensionInput;
  const cart = resource.obj;
  const actions: CartUpdateAction[] = [];

  // Получить актуальные цены из ERP
  const skus = cart.lineItems.map((li) => li.variant.sku).filter(Boolean);
  const erpPrices = await fetchErpPrices(skus, cart.customerId);

  for (const lineItem of cart.lineItems) {
    const erpPrice = erpPrices[lineItem.variant.sku!];
    if (!erpPrice) continue;

    const currentCentAmount = lineItem.price.value.centAmount;
    const erpCentAmount = Math.round(erpPrice * 100);

    if (currentCentAmount !== erpCentAmount) {
      actions.push({
        action: "setLineItemPrice",
        lineItemId: lineItem.id,
        externalPrice: {
          value: {
            centAmount: erpCentAmount,
            currencyCode: cart.totalPrice.currencyCode,
          },
        },
      });
    }
  }

  res.json({ actions });
});

Extension для Order-Create: отправка в ERP

app.post("/order-created", async (req, res) => {
  const { resource } = req.body as ExtensionInput;
  const order = resource.obj;

  try {
    const erpOrderId = await sendToErp({
      commercetoolsOrderId: order.id,
      orderNumber: order.orderNumber,
      customer: order.customerEmail,
      lines: order.lineItems.map((li) => ({
        sku: li.variant.sku,
        quantity: li.quantity,
        price: li.price.value.centAmount,
      })),
      shippingAddress: order.shippingAddress,
    });

    // Сохранить ERP ID как custom field заказа
    res.json({
      actions: [
        {
          action: "setCustomField",
          name: "erpOrderId",
          value: erpOrderId,
        },
      ],
    });
  } catch (err) {
    // Не отклоняем создание заказа при ошибке ERP —
    // лучше записать в очередь и обработать асинхронно
    await enqueueForRetry({ orderId: order.id, error: err });
    res.json({ actions: [] });
  }
});

Деплой Extension-сервиса

Extension должен отвечать за 2000 мс. Рекомендуемые варианты деплоя:

  • AWS Lambda + API Gateway — холодный старт ≤ 200мс при provisioned concurrency
  • Google Cloud Run — min-instances=1 исключает холодный старт
  • Kubernetes — если уже есть кластер
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
EXPOSE 3000
CMD ["node", "dist/server.js"]

Мониторинг и отладка

commercetools логирует все Extension-вызовы в Merchant Center → Developer → Extension Logs (хранит 7 дней). Каждый лог содержит:

  • Тело запроса (payload)
  • HTTP-статус ответа Extension
  • Тело ответа
  • Время выполнения

При timeout или 5xx от Extension операция отклоняется — это жёсткое поведение, которое нельзя изменить. Поэтому Extension-сервис должен быть стабильнее основного API.

Сроки разработки

Extension Сложность Срок
Валидация корзины Низкая 1–2 дня
Пересчёт цен из ERP Высокая 3–5 дней
Order → ERP интеграция Средняя 2–4 дня
Payment статусы синхронизация Средняя 2–3 дня
Кастомные скидки + промокоды Высокая 4–6 дней