commerce-app-webhooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Configure Commerce App Webhooks

配置Commerce应用Webhooks

Adds or modifies webhook interceptors in an existing
app.commerce.config.ts
. Webhooks intercept Commerce operations — you can validate input, append data, or modify behavior before or after an operation executes. Other extensibility domains (events, business config) are added separately via their own skills.
在现有的
app.commerce.config.ts
中添加或修改webhook拦截器。 Webhooks可拦截Commerce操作——你可以在操作执行前后验证输入、追加数据或修改行为。 其他扩展领域(事件、业务配置)需通过各自的技能单独添加。

Prerequisites

前提条件

  • Verify the app is scaffolded and initialized, not merely that the config exists. Require both:
    • app.commerce.config.ts
      present in the project root, and
    • the project initialized — signalled by the generated
      src/commerce-extensibility-1/
      directory and installed
      node_modules
      (the
      @adobe/aio-commerce-lib-app
      dependency).
  • If
    app.commerce.config.ts
    is missing, stop and invoke
    commerce-app-init
    first (it writes the config, then runs init).
  • If the config is present but the project is not initialized (no
    src/commerce-extensibility-1/
    or
    node_modules
    ), run
    npx @adobe/aio-commerce-lib-app init
    before continuing. Init is idempotent — it finds the existing config, skips the interactive prompts, installs dependencies, and generates the project files.
  • Actions can be authored in TypeScript only once the project has the TypeScript build setup (
    webpack-config.cjs
    + root
    tsconfig.json
    ) that
    init
    scaffolds for a TypeScript Commerce config — see
    commerce-app-init
    . Otherwise, author actions in JavaScript.
  • 验证应用已搭建并初始化,而不仅仅是存在配置文件。需同时满足:
    • 项目根目录下存在
      app.commerce.config.ts
      并且
    • 项目已完成初始化——标志为生成了
      src/commerce-extensibility-1/
      目录和已安装的
      node_modules
      (包含
      @adobe/aio-commerce-lib-app
      依赖)。
  • 如果
    app.commerce.config.ts
    缺失,请先停止并调用
    commerce-app-init
    (它会生成配置文件,然后执行初始化)。
  • 如果配置文件存在但项目未初始化(没有
    src/commerce-extensibility-1/
    node_modules
    ),请先运行
    npx @adobe/aio-commerce-lib-app init
    再继续。初始化是幂等操作——它会找到现有配置,跳过交互式提示,安装依赖并生成项目文件。
  • 只有当项目具备TypeScript构建环境(
    webpack-config.cjs
    + 根目录
    tsconfig.json
    ,由
    init
    为TypeScript Commerce配置搭建)时,才能用TypeScript编写动作,详情见
    commerce-app-init
    。否则,请用JavaScript编写动作。

Step 1 — Understand intent

步骤1 — 明确需求

Ask the user what they want to intercept and how:
  • What operation: the
    webhook_method
    (the Commerce operation, e.g.,
    plugin.magento.catalog_product.save
    ) and
    webhook_type
    (
    before
    or
    after
    )
  • How the handler is reached: either a runtime action in this app (
    runtimeAction: "<package>/<action>"
    ) or an explicit external URL (
    webhook.url
    ) — these are mutually exclusive
  • Category (optional):
    validation
    (block if invalid),
    append
    (add data), or
    modification
    (alter data) — used for conflict detection
  • Batch and hook identifiers:
    batch_name
    groups related hooks;
    hook_name
    uniquely identifies this hook within the batch
询问用户想要拦截的内容及方式:
  • 操作类型
    webhook_method
    (Commerce操作,例如
    plugin.magento.catalog_product.save
    )和
    webhook_type
    before
    after
  • 处理器访问方式:要么是本应用中的Runtime动作
    runtimeAction: "<package>/<action>"
    ),要么是明确的外部URL
    webhook.url
    )——二者互斥
  • 类别(可选):
    validation
    (验证不通过则阻止)、
    append
    (添加数据)或
    modification
    (修改数据)——用于冲突检测
  • 批次与钩子标识符
    batch_name
    用于分组相关钩子;
    hook_name
    用于在批次内唯一标识该钩子

Step 2 — Derive config values

步骤2 — 推导配置值

Apply the following validation rules before writing. Surface any issues to the user before proceeding.
FieldConstraint
batch_name
[a-zA-Z0-9_]+
only — no hyphens, dots, or spaces
hook_name
[a-zA-Z0-9_]+
only — no hyphens, dots, or spaces
category
Optional; must be
validation
,
append
, or
modification
runtimeAction
<package>/<action>
format; mutually exclusive with
webhook.url
webhook.url
Must be a valid absolute URL (
https://...
); mutually exclusive with
runtimeAction
label
Required, non-empty
description
Required, non-empty
method
Required HTTP method (e.g.,
POST
)
timeout
/
soft_timeout
Optional; positive integer (milliseconds)
priority
/
batch_order
Optional; positive integer
在写入前应用以下验证规则。在继续操作前向用户说明任何问题。
字段约束条件
batch_name
仅允许
[a-zA-Z0-9_]+
——不允许连字符、点号或空格
hook_name
仅允许
[a-zA-Z0-9_]+
——不允许连字符、点号或空格
category
可选;必须为
validation
append
modification
runtimeAction
<package>/<action>
格式;与
webhook.url
互斥
webhook.url
必须是有效的绝对URL(
https://...
);与
runtimeAction
互斥
label
必填,不能为空
description
必填,不能为空
method
必填HTTP方法(例如
POST
timeout
/
soft_timeout
可选;正整数(毫秒)
priority
/
batch_order
可选;正整数

Step 3 — Update
app.commerce.config.ts

步骤3 — 更新
app.commerce.config.ts

Add entries to the top-level
webhooks
array (or create it), preserving all other domains. If the config already has a
webhooks
key, append to it rather than replacing it.
Minimal examples:
ts
// Runtime action handler (handler lives in this app)
webhooks: [
  {
    label: "Validate Product Save",
    description: "Validates product data before saving.",
    category: "validation", // optional
    runtimeAction: "my-package/validate-product", // <package>/<action>
    webhook: {
      webhook_method: "plugin.magento.catalog_product.save",
      webhook_type: "before",
      batch_name: "my_app", // [a-zA-Z0-9_]+ only
      hook_name: "validate_product", // [a-zA-Z0-9_]+ only
      method: "POST",
    },
  },
];

// URL handler (external endpoint)
webhooks: [
  {
    label: "Fraud Check",
    description: "Calls external fraud service before order placement.",
    webhook: {
      webhook_method: "plugin.magento.sales_order.place",
      webhook_type: "before",
      batch_name: "my_app",
      hook_name: "fraud_check",
      method: "POST",
      url: "https://fraud.example.com/check", // inside webhook object, not top level
    },
  },
];
Each entry also accepts an optional
env
array (
"paas"
/
"saas"
) to scope it to specific Commerce environments. When omitted, the webhook applies to all environments; when set, it is only subscribed at install time on the listed environments.
See assets/webhooks-config.ts for the full annotated reference.
在顶层
webhooks
数组中添加条目(若不存在则创建),保留所有其他配置域。如果配置中已有
webhooks
键,请追加而非替换现有内容。
最简示例:
ts
// Runtime动作处理器(处理器位于本应用内)
webhooks: [
  {
    label: "Validate Product Save",
    description: "Validates product data before saving.",
    category: "validation", // optional
    runtimeAction: "my-package/validate-product", // <package>/<action>
    webhook: {
      webhook_method: "plugin.magento.catalog_product.save",
      webhook_type: "before",
      batch_name: "my_app", // [a-zA-Z0-9_]+ only
      hook_name: "validate_product", // [a-zA-Z0-9_]+ only
      method: "POST",
    },
  },
];

// URL处理器(外部端点)
webhooks: [
  {
    label: "Fraud Check",
    description: "Calls external fraud service before order placement.",
    webhook: {
      webhook_method: "plugin.magento.sales_order.place",
      webhook_type: "before",
      batch_name: "my_app",
      hook_name: "fraud_check",
      method: "POST",
      url: "https://fraud.example.com/check", // inside webhook object, not top level
    },
  },
];
每个条目还接受可选的
env
数组(
"paas"
/
"saas"
),用于限定到特定Commerce环境。省略时,webhook适用于所有环境;设置后,仅在安装时订阅到列出的环境。
完整带注释的参考配置请见assets/webhooks-config.ts

Creating the handler action

创建处理器动作

For webhook entries that use
runtimeAction
, create the action file under
src/actions/
and register it in
app.config.yaml
.
对于使用
runtimeAction
的webhook条目,请在
src/actions/
下创建动作文件,并在
app.config.yaml
中注册。

Register the action

注册动作

Add a user-defined package to
src/commerce-extensibility-1/ext.config.yaml
alongside the existing
app-management
package. Use any name except
app-management
(reserved by the framework):
yaml
undefined
src/commerce-extensibility-1/ext.config.yaml
中添加用户自定义包,与现有
app-management
包并列。使用除
app-management
之外的任意名称(该名称由框架保留):
yaml
undefined

src/commerce-extensibility-1/ext.config.yaml

src/commerce-extensibility-1/ext.config.yaml

(add below the auto-generated app-management package)

(添加到自动生成的app-management包下方)

runtimeManifest: packages: app-management: # ... auto-generated — do not edit my-app: # your package name — any name except "app-management" actions: validate-product: function: actions/validate-product/index.js # relative to src/commerce-extensibility-1/ web: "yes" runtime: nodejs:24 annotations: require-adobe-auth: true

The `<package>/<action>` format in `runtimeAction` maps directly: `my-app/validate-product` → package `my-app`, action `validate-product`.
runtimeManifest: packages: app-management: # ... 自动生成内容——请勿编辑 my-app: # 你的包名称——除"app-management"外的任意名称 actions: validate-product: function: actions/validate-product/index.js # 相对于src/commerce-extensibility-1/的路径 web: "yes" runtime: nodejs:24 annotations: require-adobe-auth: true

`runtimeAction`中的`<package>/<action>`格式直接对应:`my-app/validate-product` → 包`my-app`,动作`validate-product`。

Handler skeleton

处理器骨架

typescript
// src/commerce-extensibility-1/actions/validate-product/index.ts
import {
  ok,
  successOperation,
  exceptionOperation,
  addOperation,
  replaceOperation,
  removeOperation,
} from "@adobe/aio-commerce-lib-webhooks/responses";

export async function main(params: Record<string, unknown>) {
  // params contains the Commerce operation payload

  // Allow the operation to proceed
  return ok(successOperation());

  // Block the operation (validation failure)
  // return ok(exceptionOperation("Product SKU is required"));

  // Append data to the operation result
  // return ok(addOperation("result/custom_field", { value: "appended" }));

  // Modify a field in the result
  // return ok(replaceOperation("result/price", 99.99));

  // Remove a field from the result
  // return ok(removeOperation("result/unwanted_field"));
}
Operation types:
ResponseEffect
successOperation()
Allow — operation proceeds unchanged
exceptionOperation(message)
Block — operation is rejected with this message
addOperation(path, value)
Append data at
path
in the result
replaceOperation(path, value)
Replace the value at
path
in the result
removeOperation(path)
Remove the field at
path
from the result
typescript
// src/commerce-extensibility-1/actions/validate-product/index.ts
import {
  ok,
  successOperation,
  exceptionOperation,
  addOperation,
  replaceOperation,
  removeOperation,
} from "@adobe/aio-commerce-lib-webhooks/responses";

export async function main(params: Record<string, unknown>) {
  // params包含Commerce操作的负载

  // 允许操作继续执行
  return ok(successOperation());

  // 阻止操作(验证失败)
  // return ok(exceptionOperation("Product SKU is required"));

  // 向操作结果追加数据
  // return ok(addOperation("result/custom_field", { value: "appended" }));

  // 修改结果中的字段
  // return ok(replaceOperation("result/price", 99.99));

  // 移除结果中的字段
  // return ok(removeOperation("result/unwanted_field"));
}
操作类型:
响应效果
successOperation()
允许——操作按原样继续执行
exceptionOperation(message)
阻止——操作被拒绝并返回该消息
addOperation(path, value)
在结果的
path
位置追加数据
replaceOperation(path, value)
替换结果
path
位置的值
removeOperation(path)
从结果中移除
path
位置的字段

Step 4 — Validate

步骤4 — 验证

Build the project to confirm the updated config is valid:
sh
aio app build
A build failure with a validation error points directly to the offending config field.
构建项目以确认更新后的配置有效:
sh
aio app build
包含验证错误的构建失败会直接指向有问题的配置字段。

Common Issues

常见问题

  • batch_name
    or
    hook_name
    rejected
    : Use underscores as separators (
    my_app
    ,
    validate_product_save
    ) — hyphens, dots, and spaces are not accepted.
  • Both
    runtimeAction
    and
    webhook.url
    set
    : These are mutually exclusive — use
    runtimeAction
    when the handler lives in this app;
    webhook.url
    for an external endpoint.
  • url
    at wrong level
    : For URL-based entries,
    url
    must be inside the nested
    webhook
    object, not at the top level alongside
    label
    .
  • app-management
    package name conflict
    : The framework generates this package in
    ext.config.yaml
    on every build. Use any other name for your own actions.
  • Function path is relative to
    src/commerce-extensibility-1/
    : Do not use
    src/...
    or project-root-relative paths.
    actions/validate-product/index.js
    resolves correctly;
    src/commerce-extensibility-1/actions/validate-product/index.js
    does not.
  • defineConfig
    not found
    : Ensure
    @adobe/aio-commerce-lib-app
    is installed and
    defineConfig
    is imported from
    @adobe/aio-commerce-lib-app/config
    .
  • batch_name
    hook_name
    被拒绝
    :使用下划线作为分隔符(
    my_app
    validate_product_save
    )——不接受连字符、点号和空格。
  • 同时设置了
    runtimeAction
    webhook.url
    :二者互斥——当处理器位于本应用内时使用
    runtimeAction
    ;外部端点使用
    webhook.url
  • url
    层级错误
    :基于URL的条目中,
    url
    必须嵌套在
    webhook
    对象内,而非与
    label
    同级的顶层。
  • app-management
    包名称冲突
    :框架会在每次构建时在
    ext.config.yaml
    中生成该包。请为自己的动作使用其他名称。
  • 函数路径相对于
    src/commerce-extensibility-1/
    :请勿使用
    src/...
    或项目根目录相对路径。
    actions/validate-product/index.js
    路径有效;
    src/commerce-extensibility-1/actions/validate-product/index.js
    无效。
  • 找不到
    defineConfig
    :确保已安装
    @adobe/aio-commerce-lib-app
    ,并从
    @adobe/aio-commerce-lib-app/config
    导入
    defineConfig

Quality Bar

质量标准

  • aio app build
    completes without errors
  • aio app build
    无错误完成

Chaining

后续操作

After
aio app build
passes:
  • Add merchant settings — invoke
    commerce-app-business-config
    to expose configurable settings in Commerce Admin
  • Add event subscriptions — invoke
    commerce-app-eventing
    to subscribe to Commerce or external events
  • Extend the Admin UI — invoke
    commerce-app-admin-ui
    to add custom columns, mass actions, order view buttons, or menu entries in Commerce Admin
  • Add persistent storage — invoke
    commerce-app-storage
    to back webhook handlers with queryable DB storage
aio app build
通过后:
  • 添加商家设置——调用
    commerce-app-business-config
    在Commerce Admin中公开可配置的设置
  • 添加事件订阅——调用
    commerce-app-eventing
    订阅Commerce或外部事件
  • 扩展Admin UI——调用
    commerce-app-admin-ui
    在Commerce Admin中添加自定义列、批量操作、订单查看按钮或菜单项
  • 添加持久化存储——调用
    commerce-app-storage
    为webhook处理器提供可查询的数据库存储支持

References

参考资料

  • assets/webhooks-config.ts — Reference config showing both runtime action and URL-based webhook entry shapes
  • assets/webhooks-config.ts——展示Runtime动作和基于URL的webhook条目格式的参考配置