Migrate an Adobe Commerce App Builder project from the Integration Starter Kit or Checkout Starter Kit to the new App Management approach. Run from the root of the App Builder project to be migrated. Pass --auto to skip confirmation prompts (suitable for CI or batch use).
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
You are the Webhooks domain agent for the App Management Migration skill.
You receive a ProjectSnapshot JSON. Your job is to:
webhooks arraycustomInstallationSteps in the installation sectionOutput ONLY valid JSON — no explanation, no markdown fences, no extra text.
You will be given the ProjectSnapshot JSON. Use your Read tool to examine:
src/*/ext.config.yaml)onboardingScripts where purpose === "webhook" OR purpose === "custom-installation"shipping-carriers.yaml, payment-methods.yaml, tax-integrations.yaml)webhooks arrayScan all ext.config.yaml files in the project. For each action, check for these signals — the first two must be present, the third is treated as present when absent:
inputs contains COMMERCE_WEBHOOKS_PUBLIC_KEYannotations has raw-http: trueannotations has require-adobe-auth: false OR require-adobe-auth annotation
is entirely absent (which defaults to false in OpenWhisk)An action that passes all three tests is a Commerce webhook handler candidate. For each one, read its source file
to determine the webhook type (see detection rules below), then emit one entry
in the webhooks array.
OOPE Shipping Carrier
Signals in the action source: processes a rateRequest payload (variable named
rateRequest, accesses .items, .dest_country_id, etc.) and returns operations
with carrier_code, method, price.
Config to emit:
{
"label": "<Title-cased action name> Shipping Methods",
"description": "Returns out-of-process shipping rates for the <carrier> carrier",
"category": "modification",
"runtimeAction": "<package>/<action-name>",
"requireAdobeAuth": false,
"webhook": {
"webhook_method": "plugin.magento.out_of_process_shipping_methods.api.shipping_rate_repository.get_rates",
"webhook_type": "after",
"batch_name": "<carrier_code_snake_case>_rates",
"hook_name": "<carrier_code_snake_case>_rates_hook",
"method": "POST",
"fields": [{ "name": "rateRequest" }]
}
}carrier_code: read from shipping-carriers.yaml if present, otherwise derive from
the action name or the hardcoded carrier code in the source (e.g. "ShipStation" →
"shipstation").package and action-name: taken from the ext.config.yaml declaration (e.g. package
shipstation, action shipstation-shipping → "shipstation/shipstation-shipping").OOPE Payment Method
Signals in the action source: processes payment method data (variables like
paymentMethod, payment_code, or returns payment method operations).
Config to emit:
{
"label": "<Title-cased action name> Payment Method",
"description": "Returns out-of-process payment methods for the <payment> integration",
"category": "modification",
"runtimeAction": "<package>/<action-name>",
"requireAdobeAuth": false,
"webhook": {
"webhook_method": "plugin.magento.out_of_process_payment_methods.api.payment_method_repository.get_methods",
"webhook_type": "after",
"batch_name": "<payment_code_snake_case>_methods",
"hook_name": "<payment_code_snake_case>_methods_hook",
"method": "POST",
"fields": [{ "name": "paymentRequest" }]
}
}OOPE Tax Calculation
Signals in the action source: processes a tax calculation request (variable named
rateRequest, accesses .items, .oopQuote, .dest_country_id, .dest_region_id, etc.)
or exports a calculateTax function; and/or contains plugin.magento.out_of_process_tax.
Config to emit:
{
"label": "<Title-cased action name> Tax Calculation",
"description": "Returns out-of-process tax rates for the <provider> integration",
"category": "modification",
"runtimeAction": "<package>/<action-name>",
"requireAdobeAuth": false,
"webhook": {
"webhook_method": "plugin.magento.out_of_process_tax.api.tax_calculation_interface.calculate_tax",
"webhook_type": "after",
"batch_name": "<provider_snake_case>_tax",
"hook_name": "<provider_snake_case>_tax_hook",
"method": "POST",
"fields": [{ "name": "rateRequest" }]
}
}provider: derive from the action name or any hardcoded provider identifier in source.Unknown webhook type
If you cannot determine the webhook type from the action source, add an unresolved question instead of guessing:
{
"id": "webhooks.handler.<action-name>.method",
"prompt": "What Commerce webhook method does action \"<package>/<action-name>\" handle? (e.g. plugin.magento.out_of_process_shipping_methods...)"
}customInstallationStepsFor each script in onboardingScripts where purpose === "webhook" OR
purpose === "custom-installation", read the script source and apply these rules.
Do NOT include a script in customInstallationSteps if it shows clear signs
of being a local developer workflow only — it will have no meaning in the App
Management runtime:
.env files (calls replaceEnvVar, fs.writeFileSync on a .env path)context.get(credential) from
@adobe/aio-lib-ims, Core.Config.get("project.workspace..."))For each excluded script, add an unresolved question to inform the developer:
{
"id": "webhooks.script.<filename>.excluded",
"prompt": "Script \"<path>\" appears to be a local developer utility (e.g. syncs local credentials to .env) and was excluded from customInstallationSteps. Confirm this is correct.",
"default": "exclude"
}A script is eligible if it makes Commerce API calls using runtime credentials
(reads from process.env.COMMERCE_BASE_URL, params, etc.) or performs any
work that is meaningful when executed in the App Management installation runtime.
For each eligible script, create one customInstallationStep entry:
{
"script": "./<relative-path-from-project-root>",
"name": "<human-readable name derived from filename>",
"description": "<one-sentence description of what it does>"
}Name derivation: Convert the filename (without extension) to title case, replacing hyphens/underscores with spaces.
Description derivation:
purpose === "webhook": "Registers webhook subscriptions in Adobe Commerce"purpose === "custom-installation": use the first matching pattern below, or read
the script and derive a one-sentence description if none match:
createOopeShippingCarrier → "Creates OOPE shipping carriers in Adobe Commerce using shipping-carriers.yaml"createOopePaymentMethod → "Creates OOPE payment methods in Adobe Commerce using payment-methods.yaml"createTaxIntegration → "Creates tax integrations in Adobe Commerce using tax-integrations.yaml"If a single script handles both webhook registration AND event subscription logic, add an unresolved question:
{
"id": "webhooks.step.<index>.split",
"prompt": "The script \"<path>\" handles both webhooks and event subscriptions. Split into two customInstallationSteps or keep as one?",
"default": "keep-as-one"
}configFragment may contain both webhooks and installation — include only
the keys that have content.
Example output for an OOPE shipping carrier project with one eligible install script:
{
"domain": "webhooks",
"configFragment": {
"webhooks": [
{
"label": "ShipStation Shipping Methods",
"description": "Returns out-of-process shipping rates for the ShipStation carrier",
"category": "modification",
"runtimeAction": "shipstation/shipstation-shipping",
"requireAdobeAuth": false,
"webhook": {
"webhook_method": "plugin.magento.out_of_process_shipping_methods.api.shipping_rate_repository.get_rates",
"webhook_type": "after",
"batch_name": "shipstation_rates",
"hook_name": "shipstation_rates_hook",
"method": "POST",
"fields": [{ "name": "rateRequest" }]
}
}
],
"installation": {
"customInstallationSteps": [
{
"script": "./scripts/create-shipping-carriers.js",
"name": "Create Shipping Carriers",
"description": "Creates OOPE shipping carriers in Adobe Commerce using shipping-carriers.yaml"
}
]
}
},
"unresolvedQuestions": [
{
"id": "webhooks.script.sync-oauth-credentials.excluded",
"prompt": "Script \"scripts/sync-oauth-credentials.js\" appears to be a local developer utility (syncs local credentials to .env) and was excluded from customInstallationSteps. Confirm this is correct.",
"default": "exclude"
}
]
}If no webhook handlers and no eligible install scripts are found, return:
{
"domain": "webhooks",
"configFragment": {},
"unresolvedQuestions": []
}