api_version = "2026-04", Shopify CLI 4.8.0, app 6981071, dev store gw-qa-test-77.myshopify.com.
[[extensions.targeting]]
module = "./src/IntentExtension.tsx"
target = "admin.app.intent.render"
tools = "./tools.json"
instructions = "./instructions.md"
[[extensions.targeting.intents]]
type = "application/loyalty-program"
action = "edit"
schema = "./schema.edit.json"
What works. Sidekick invokes the intent, the panel renders, shopify.intents.request.value carries the input, a runtime-registered tool stages the change, the merchant clicks Save and the app writes to its backend.
How I resolve it — following the docs (callback not async, awaited promise handed to event.waitUntil) and the pattern in Shopify/discounts-reference-app PR #78:
onClick={(event) => {
const p = (async () => {
await writeToBackend();
await shopify.intents.response.ok({ setting, target });
})();
event.waitUntil?.(p);
}}
The promise returned by response.ok() resolves. I record that in telemetry, so delivery is confirmed rather than assumed — 4 of 4 sessions delivered.
Two things then don’t happen:
-
The surface stays on screen. The docs say “The invoking surface closes the modal, so you don’t need to navigate yourself”, but this target is described as rendering inline. Is closing expected for an inline surface, or is the panel meant to remain in the conversation?
response.closed()behaves the same way. -
Sidekick says nothing afterwards — 0 of 5 sessions. The only message the merchant sees is the one built from the tool’s staging result, and it appears before they click Save. Is the invoking turn expected to resume and surface
response.data, or does resolution hand control back with no merchant-visible effect? If it’s the latter, the extension surface is the only place an outcome can be shown, which changes how these panels should be designed.
Also: shopify.intents.hasProvider exists at runtime but appears in neither the docs nor @shopify/ui-extensions@2026.4.0, whose Intents interface carries only launchUrl and invoke — no request, no response. What does it report? It looks like it would answer question 2 directly.
Runtime keys observed on this target:
intents.launchUrl, intents.invoke, intents.hasProvider, intents.request, intents.response
response.ok, response.error, response.closed