# Emdash Mika Compact LLM Context Use this file for a compact high-signal set of Mika docs facts. Some specialized pages are summary-only with source anchors. Fetch https://mika.bnomei.com/llms-full.txt for the complete generated docs text. Public boundary: Mika public plugin JSON reads are `catalog.sellables` (`catalogSellables`, `GET /_emdash/api/plugins/mika/catalog/sellables`) and `stock.availability` (`sellableAvailability`, `GET /_emdash/api/plugins/mika/sellables/availability`). Browser mutations use host-owned Astro Actions. Checkout, account, payment, admin, webhook, and agent-tool flows require host-owned auth, policy, confirmation, idempotency, and provider wiring. Recommended paths: first look is Overview -> Compatibility And Publication -> Quickstart: Seeded Template. Existing app wiring is Install -> First Product Page -> First Integration Checklist. Storefront setup is Product Authoring -> Astro Storefront -> Cart, Wishlist, And Checkout -> Account And Downloads. Providers and backend is Backend And Provider -> Production Backend Wiring -> Stripe Provider -> Stripe And Webhook Cookbook. AI commerce is Agent-Ready Commerce -> Agent-Ready Storefront -> Product JSON-LD -> LLMs And Manifest -> ACP Checkout. Operations is Deployment Matrix -> Deployment And Maintenance -> Cloudflare Variant -> Admin Actions -> Troubleshooting. # Getting Started Path: /getting-started/ URL: https://mika.bnomei.com/getting-started/ First reading path for installing, running, and wiring Mika into an Astro + EmDash host. Start here when you are new to Mika. Keep the first success small: understand the boundary, confirm package state, run the seeded template, then wire Mika into an existing Astro + EmDash app when you are ready. Read `src/` paths as files in the host app. Package imports come from `@bnomei/emdash-mika`; copied template files become host-owned after copy. ## Run The Seeded Template - [1. Overview](https://mika.bnomei.com/getting-started/overview/): Learn what Mika provides and what stays host-owned. - [2. Compatibility](https://mika.bnomei.com/getting-started/compatibility-publication/): Check package state, local workspace mode, and peer ranges before install. - [3. Seeded Template](https://mika.bnomei.com/getting-started/quick-start-template/): Run the sibling host app and verify storefront, admin, and agent paths. ## Wire An Existing App Use this path after you have an Astro + EmDash app to integrate: - [4. Install](https://mika.bnomei.com/getting-started/install/): Register Mika with EmDash and choose the first backend strategy. - [5. Product Page](https://mika.bnomei.com/getting-started/first-product-page/): Connect one host product route to Mika sellables and purchase components. - [6. First Integration Checklist](https://mika.bnomei.com/guides/first-integration-checklist/): Walk the file copy, config, product page, and verification sequence. After this path, use [Product Authoring](https://mika.bnomei.com/guides/product-authoring/) for content-to-sellable mapping, [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) for copied Actions and UI, and [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/) when real provider and repository wiring starts. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/README.md` - ⓣ `../emdash-mika-template/package.json` - ⓣ `../emdash-mika-template/README.md` # Overview Path: /getting-started/overview/ URL: https://mika.bnomei.com/getting-started/overview/ What Mika is, what it provides, and what remains host-owned. Mika is agent-ready commerce for content-led Astro and EmDash storefronts. In practical terms, it gives a host storefront commerce contracts, form actions, provider boundaries, and metadata that humans, crawlers, and agents can read consistently. It provides typed commerce primitives, Astro Actions, route contracts, provider interfaces, operation descriptors, and copyable Astro template files for storefronts that need products, variants, stock, carts, wishlists, checkout handoff, account links, subscriptions, downloads, licenses, provider webhooks, and agent-readable metadata. Mika is not a full commerce platform. The host app owns product content, routing, layout, auth/session policy, provider credentials, tax and shipping rules, rate limits, deployment, support, and protected agent/tool surfaces. Keep one rule in mind while reading these docs: Mika exports contracts and copyable files; the host Astro project decides where those files live and how requests are allowed to move through them. Use the [Integration File Map](https://mika.bnomei.com/concepts/integration-map/) whenever a guide mentions `astro.config.mjs`, `src/actions/`, copied template pages, EmDash plugin routes, or provider wiring. ## Where Examples Come From Most examples in these docs are one of three things: - Package exports from `../emdash-mika/package.json`, such as `@bnomei/emdash-mika/astro`, `@bnomei/emdash-mika/astro-actions`, `@bnomei/emdash-mika/server`, and `@bnomei/emdash-mika/stripe`. - Copyable Astro files from `../emdash-mika/src/templates/astro/**`, which become host-owned `src/actions`, `src/pages`, `src/components`, `src/lib`, and `src/styles` files after copying. - Runnable host-app examples from `../emdash-mika-template/**`, which show how those copied files fit into an Astro + EmDash project. When a guide shows a path under `src/`, read it as a host app path unless the guide explicitly says it is inside the package template source. ## What To Read Next For a first look, read and run: 1. [Compatibility And Publication](https://mika.bnomei.com/getting-started/compatibility-publication/) to choose local workspace or published install mode. 2. [Quickstart: Seeded Template](https://mika.bnomei.com/getting-started/quick-start-template/) to run a complete source-backed host app. For an existing Astro + EmDash app, continue with: 1. [Install](https://mika.bnomei.com/getting-started/install/) to register the plugin and identify the host-owned API and Actions files. 2. [First Product Page](https://mika.bnomei.com/getting-started/first-product-page/) to connect one host route to Mika sellables. 3. [First Integration Checklist](https://mika.bnomei.com/guides/first-integration-checklist/) to verify the first integration slice. Then choose a deeper path: - Storefront UI and Actions: [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/). - Backend repositories and providers: [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/). - Agent-readable commerce: [Agent-Ready Storefront](https://mika.bnomei.com/guides/agent-ready-storefront/). - Exact contracts: [Package Exports](https://mika.bnomei.com/reference/package-exports/). ## Use Mika When - You have content-led product pages and need commerce behavior next to them. - You want Astro-native HTML forms and Actions instead of a hidden app route system. - You need public product metadata that agrees with visible price, availability, and variant state. - You want semantic operation descriptors that can later project into ACP, UCP, MCP, OpenAPI, or other host-owned protocols. ## Source Anchor Key Source anchors use these glyphs to separate the main source sets: - ⓟ core package repo: `../emdash-mika/**`. - ⓐ copyable Astro template files inside the core package: `../emdash-mika/src/templates/astro/**`. - ⓣ seeded GitHub template repo: [`bnomei/emdash-mika-template`](https://github.com/bnomei/emdash-mika-template), local path `../emdash-mika-template/**`. ## External References - [Astro Actions](https://docs.astro.build/en/guides/actions/) for the `src/actions/index.ts` pattern Mika builds on. - [EmDash getting started](https://docs.emdashcms.com/getting-started) for the Astro + EmDash project shape Mika expects to join. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/README.md` - ⓐ `../emdash-mika/src/templates/astro/examples/release-slice.md` - ⓣ `../emdash-mika-template/README.md` # Compatibility And Publication Path: /getting-started/compatibility-publication/ URL: https://mika.bnomei.com/getting-started/compatibility-publication/ Current Mika package state, local workspace install path, and Astro/EmDash peer ranges. Use this page before copying install commands into a new app. It answers one question: should the host depend on a published package, or on the sibling local package in this workspace? The core package source currently identifies `@bnomei/emdash-mika` as version `0.0.0`. The sibling seeded template depends on it with `file:../emdash-mika` and rebuilds the local package before dev, build, preview, typecheck, test, and seed commands. Treat registry availability as a release-time check, not a docs constant. This workspace proves the local package and template relationship; a public host app should use the registry path only after a non-`0.0.0` Mika package is published and its peer ranges match the host. ## Source-Of-Truth Ranges `../emdash-mika/package.json` is authoritative for package metadata: | Surface | Current source value | | --- | --- | | Package name | `@bnomei/emdash-mika` | | Package version | `0.0.0` | | Node engine | `>=22.12.0` | | Astro peer | `^6.0.0 || ^7.0.0` | | EmDash peer | `>=0.22.0 <1.0.0` | | Stripe peer | `>=16.0.0 <21.0.0` | | Published file set | `dist` and `src/templates` | | Copyable template export | `./templates/astro/*` | The seeded GitHub template raises the local Node engine to `>=22.13.0`, uses Astro `^7.0.0`, and depends on Mika through `file:../emdash-mika`. ## Install Mode ### Local workspace Use this mode while Mika is unpublished or while developing the sibling repos together. The seeded template already depends on Mika with `file:../emdash-mika` and rebuilds the package during its lifecycle scripts. Run it from [Quickstart: Seeded Template](https://mika.bnomei.com/getting-started/quick-start-template/). In a separate host app, point the dependency at the sibling package until a public version exists: ```json { "dependencies": { "@bnomei/emdash-mika": "file:../emdash-mika", "emdash": ">=0.22.0 <1.0.0" } } ``` ### Published package Use this mode only after the package is available from the registry and the version supports your EmDash range. ```sh npm install @bnomei/emdash-mika "emdash@>=0.22.0 <1.0.0" ``` Pin EmDash inside the peer range from `../emdash-mika/package.json` when you need repeatable installs. ## Release Checklist Before documenting a public `npm install @bnomei/emdash-mika` flow as the only path: - confirm the package exists on npm; - confirm the published version is not `0.0.0`; - confirm the EmDash peer range matches the EmDash version you recommend; - replace `file:../emdash-mika` in template docs or clearly mark it as local development; - rerun the docs build and inspect `dist/llms.txt` so agents receive the same status. Next: [Quickstart: Seeded Template](https://mika.bnomei.com/getting-started/quick-start-template/) runs the source-backed host app. Use [Install](https://mika.bnomei.com/getting-started/install/) when wiring a separate Astro + EmDash app. ## External References - [EmDash getting started](https://docs.emdashcms.com/getting-started) for EmDash's current Node and project setup guidance. - [npm package spec](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for `file:` dependencies and package metadata fields. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/README.md` - ⓣ `../emdash-mika-template/package.json` - ⓣ `../emdash-mika-template/docs/usage.md` # Quickstart: Seeded Template Path: /getting-started/quick-start-template/ URL: https://mika.bnomei.com/getting-started/quick-start-template/ Run the sibling seeded GitHub template repo and verify the main Mika storefront, admin, and agent-readable paths. The sibling [GitHub template repo](https://github.com/bnomei/emdash-mika-template), local path `../emdash-mika-template`, is the fastest source-backed first success path. It is a host Astro app that wires the local Mika package, fixture commerce data, copied storefront files, admin action fields, and agent-readable metadata. Use this quickstart to see the complete shape before copying files into another app. ## Prerequisites Use Node `>=22.13.0` for the template. It depends on the sibling Mika package through `file:../emdash-mika`, so lifecycle scripts rebuild Mika locally before dev, build, preview, typecheck, test, and seed commands. ## Run ```sh cd ../emdash-mika-template npm install npm run fixture:reset npm run dev ``` `npm run fixture:reset` resets the local template fixture state under `.emdash/`; run it only when you want the smoke app returned to seeded data. A published template should replace the local Mika path with a released npm version. Expected state after `npm run dev`: Astro starts the template app, the local Mika package has been rebuilt by the template lifecycle script, and the storefront paths below resolve from the host app. ## Smoke The Browser Paths After `npm run dev` starts, open these paths in the template app: - `/` for product listing. - `/products/mira-field-clipboard` for a product page. - `/products/thirdbase-team-pennants` for printable stock-state fixtures. - `/products/junie-sidewalk-zine-kit` for zine-kit stock and cart fixtures. - `/products/buttonwood-creator-bundle` for download, subscription, license, and stock-state fixtures. - `/?category=creator-tools` or `/?category=paper-goods&tag=printables` for homepage category/tag filters. - `/cart`, `/wishlist`, `/account`, and `/account/magic-link` for customer flows. - `/checkout/success?checkoutId=checkout_buttonwood_1001` for a seeded checkout return. - `/download/download_panel_pack_mira` for the seeded-repo download fixture; see [Template Fixture Route](https://mika.bnomei.com/guides/account-downloads/#template-fixture-route). - `/llms.txt` and `/.well-known/mika-agent.json` for agent-readable storefront metadata. - `/_emdash/admin` for the EmDash admin UI. - `/api/mika-action-contract.json` for the admin action provider contract. ## Template-Only Files The seeded repo is not just a copy of `../emdash-mika/src/templates/astro/**`. It adds host-app files that prove the integration: | File | Purpose | | --- | --- | | `src/pages/products/[slug].astro` | Host product page that loads fixture product content and renders copied Mika purchase components. | | `src/lib/mika-api.ts` | Host API entrypoint that combines fixture storefront overrides with admin/testbed behavior. | | `src/lib/mika-fixture-storefront.ts` | Fixture catalog, cart, wishlist, account, checkout, and download behavior for smoke flows. | | `src/plugins/mika-template-plugin.ts` | Native plugin entrypoint used when function overrides cannot be serialized through descriptor options. | | `src/emdash/mika-action-fields.ts` | EmDash field-button wiring for Mika admin actions. | | `src/pages/api/mika-action-contract.json.ts` | Readback endpoint for the admin action provider contract. | Use those files to learn the shape of a host integration. Do not copy testbed fixture behavior into production unless you are intentionally building a fixture app. ## Run The Template Checks The seeded GitHub template repo should pass: ```sh npm run typecheck npm run test npm run build ``` Expected result: all three commands exit successfully. Next: [Install](https://mika.bnomei.com/getting-started/install/) shows how to wire Mika into a separate Astro + EmDash app. [First Product Page](https://mika.bnomei.com/getting-started/first-product-page/) explains the same boundary in the smallest manual host route. ## Source Anchors - ⓣ `../emdash-mika-template/README.md` - ⓣ `../emdash-mika-template/package.json` - ⓣ `../emdash-mika-template/docs/testbed.md` - ⓣ `../emdash-mika-template/docs/usage.md` - ⓣ `../emdash-mika-template/src/pages/index.astro` - ⓣ `../emdash-mika-template/src/pages/products/[slug].astro` - ⓣ `../emdash-mika-template/src/lib/mika-api.ts` - ⓣ `../emdash-mika-template/src/lib/mika-fixture-storefront.ts` - ⓣ `../emdash-mika-template/src/plugins/mika-template-plugin.ts` - ⓣ `../emdash-mika-template/src/emdash/mika-action-fields.ts` - ⓣ `../emdash-mika-template/src/pages/api/mika-action-contract.json.ts` # Install Path: /getting-started/install/ URL: https://mika.bnomei.com/getting-started/install/ Install Mika, register the EmDash plugin, and identify required host wiring. Use this page to add Mika to a host Astro + EmDash app. It covers package mode, plugin registration, the first host-owned files, and the verification checks that prove the wiring exists. Check [Compatibility And Publication](https://mika.bnomei.com/getting-started/compatibility-publication/) before treating a registry install as available. In this workspace, Mika is still version `0.0.0` and the seeded template uses `file:../emdash-mika`; verify publication before making `npm install @bnomei/emdash-mika` the only documented path. ## Prerequisites - An existing Astro + EmDash app. - Node `>=22.12.0`; the seeded template uses Node `>=22.13.0`. - An install mode chosen from [Compatibility And Publication](https://mika.bnomei.com/getting-started/compatibility-publication/). - A planned `api`, either fixture overrides or a production `createMikaBackendApi()` composition. - Dynamic or server rendering for request-bound pages such as cart, account, checkout, downloads, and webhooks. When the package is published, install it in an Astro + EmDash app and pin EmDash inside Mika's current peer range: ```sh npm install @bnomei/emdash-mika "emdash@>=0.22.0 <1.0.0" ``` For local workspace development before publication, use a file dependency: ```json { "dependencies": { "@bnomei/emdash-mika": "file:../emdash-mika", "emdash": ">=0.22.0 <1.0.0" } } ``` ## Register The Plugin Register the native plugin in the host app's existing EmDash config: ```ts import { defineConfig } from "astro/config"; import emdash from "emdash/astro"; import { mikaPlugin } from "@bnomei/emdash-mika"; import { api } from "./src/lib/mika-api"; export default defineConfig({ integrations: [ emdash({ // Keep the host's database, storage, admin, and other EmDash options here. plugins: [mikaPlugin({ api })], }), ], }); ``` `api` is host-owned. Build it with `createMikaBackendApi()` and provider adapters, or supply explicit `MikaApi` method overrides for tests, fixtures, or custom backends. This registration happens in the same file where EmDash itself is configured. The official EmDash project shape keeps database, storage, plugin, and admin configuration in `astro.config.mjs`; Mika joins that plugin list rather than replacing EmDash content or Astro routing. ## Descriptor Options Versus Native Entrypoints Choose the form that matches how your host can load the Mika API: ### Direct descriptor Use this when the host API/options are safe for your descriptor path: ```ts mikaPlugin({ api }) ``` ### Native entrypoint Use this when the API is made of function overrides, or must import runtime-only local modules: ```ts // astro.config.mjs mikaPlugin({ entrypoint: "#mika-plugin" }) ``` The `#mika-plugin` module should export `createPlugin()` and call Mika's runtime `createPlugin({ api })`: ```ts // src/plugins/mika-plugin.ts import { createPlugin as createMikaPlugin } from "@bnomei/emdash-mika"; import { api } from "../lib/mika-api"; export function createPlugin(options = {}) { return createMikaPlugin({ ...options, api }); } ``` The seeded GitHub template uses `#mika-template-plugin` for this reason. Its `package.json` maps that import alias to `src/plugins/mika-template-plugin.ts`, and `astro.config.mjs` registers `mikaPlugin({ entrypoint: "#mika-template-plugin" })`. ## What You Must Wire `mikaPlugin({ api })` needs two host-owned pieces: 1. **The backend API** — `api`, composed with `createMikaBackendApi()` (repositories, providers, notifications, IDs, hashing, config). For tests or fixtures you can pass plain `MikaApiOverrides` method overrides instead of a full backend. See the Backend And Provider guide. 2. **The Astro Actions registry** — copy `src/actions/{index,mika}.ts` and export `server.mika = createMikaActions()` so browser forms can post to `actions.mika.*`. See the Astro Storefront guide. Provider secrets (Stripe keys, webhook secret, email credentials) are host-owned environment configuration. Mika ships none of them; add them when you wire each provider adapter. ## Choose A Backend Strategy For smoke tests and fixtures, explicit `MikaApiOverrides` are fine. The seeded template uses local fixture functions to prove catalog, cart, wishlist, checkout, account, download, and admin flows. For production, use `createMikaBackendApi()` with durable repository ports, a provider registry, IDs, clocks, hashing, notification hooks, defaults, and checkout config. Stripe wiring does not replace repositories; the Stripe adapter only handles provider-facing checkout, portal, invoice, refund, sync, and webhook behavior. ## Rendering And Adapters Mika's cart, account, and checkout pages are request-bound, so they export `prerender = false`. Run the host with `output: "server"` (or keep those routes dynamic in a hybrid build) behind an Astro adapter such as `@astrojs/node` or `@astrojs/cloudflare`. EmDash itself needs a database and storage adapter; the ⓣ seeded GitHub template repo uses SQLite + local files on Node, and sketches D1 + R2 on Cloudflare. Astro prerenders pages by default. A copied Mika page that reads cookies, sessions, carts, account state, or action results must render on demand. You can do that per route with `export const prerender = false`, or set `output: "server"` for the host and opt individual static pages back into prerendering. ## First Files To Create Or Copy For a new integration, the shortest useful path is: 1. `astro.config.mjs` registers EmDash and `mikaPlugin({ api })`. 2. `src/lib/mika-api.ts` exports the host-owned API implementation. 3. `src/actions/mika.ts` re-exports Mika's action factory. 4. `src/actions/index.ts` exports `server.mika = createMikaActions()` and optional host guards. 5. A host product page calls `createMika(Astro)` and renders copied purchase components. See the [Integration File Map](https://mika.bnomei.com/concepts/integration-map/) for the full import/copy distinction. ## UI Dependencies For Copied Templates The commerce contracts do not require Kumo or React, but the copyable Astro templates do. If you copy the Kumo-backed UI files, install and register the UI dependencies: ```sh npm install @cloudflare/kumo @phosphor-icons/react react react-dom @astrojs/react ``` Add `react()` to the host's existing `integrations` array; keep `emdash(...)` and any other integrations already present: ```ts import react from "@astrojs/react"; export default defineConfig({ integrations: [ react(), // Keep the host's existing integrations here. ], }); ``` Also copy or import `styles/kumo.css`. Kumo is the template UI layer; it is not Mika's commerce runtime. ## Verify The Install After the first files exist, run the same checks as the [First Integration Checklist](https://mika.bnomei.com/guides/first-integration-checklist/): - build the host app; - load one product page that calls `createMika(Astro)`; - submit one `actions.mika.cart.add` form; - confirm `Astro.getActionResult(actions.mika.cart.add)` renders feedback; - confirm checkout start either returns a provider redirect or a clear provider/configuration error; - open `/_emdash/api/plugins/mika/catalog/sellables?collection=products&id=` and `/_emdash/api/plugins/mika/sellables/availability?sellableId=` as public reads, using IDs from your host data; - keep protected mutation routes behind Actions or host-owned endpoints. If you have not seen a complete source-backed host app yet, run the [seeded template quickstart](https://mika.bnomei.com/getting-started/quick-start-template/). After the existing app is registered, continue with [First Product Page](https://mika.bnomei.com/getting-started/first-product-page/). ## Peer Surface Mika targets Astro, EmDash, TypeScript, and optional UI/provider helpers. Check `../emdash-mika/package.json` for the current peer ranges before publishing install instructions. ## External References - [EmDash getting started](https://docs.emdashcms.com/getting-started) for EmDash's `astro.config.mjs`, database, storage, and Live Collections setup. - [Astro on-demand rendering](https://docs.astro.build/en/guides/on-demand-rendering/) for adapters, dynamic pages, and `output: "server"`. - [Astro routing reference](https://docs.astro.build/en/reference/routing-reference/#prerender) for `export const prerender = false`. ## Source Anchors - ⓟ `../emdash-mika/README.md` - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/src/plugin.ts` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓣ `../emdash-mika-template/astro.config.mjs` - ⓣ `../emdash-mika-template/src/plugins/mika-template-plugin.ts` - ⓣ `../emdash-mika-template/package.json` # First Product Page Path: /getting-started/first-product-page/ URL: https://mika.bnomei.com/getting-started/first-product-page/ The first host-owned product page shape that uses Mika sellables and purchase components. Use this page after Mika is registered and `actions.mika.*` exists. It shows the smallest host-owned product page shape: resolve host content, ask Mika for sellables, render product metadata, then render purchase forms. Product pages stay host-owned. Mika supplies the request-bound helper, form contracts, sellable data, and copyable purchase components. ## Prerequisites - Mika is registered in the host EmDash config. - `createMikaActions()` is exported as `server.mika`. - The host can look up a product by route slug. - The product purchase component dependency set from [First Integration Checklist](https://mika.bnomei.com/guides/first-integration-checklist/) is copied, including `src/lib/routes.ts`; `ProductStructuredData.astro` is copied too. - If rendering copied Kumo-backed components, `@cloudflare/kumo`, React, `@astrojs/react`, and `src/styles/kumo.css` are installed and imported. - The product route can render on demand with `export const prerender = false` or server output. The usual first page does this: 1. Fetch the host product entry. 2. Create a request-bound Mika helper with `createMika(Astro)`. 3. Load sellables with `Mika.catalog.sellables(collection, id)`. 4. Render visible host product content. 5. Render `ProductStructuredData` with matching product and offer metadata. 6. Render `ProductPurchase` for variants, stock state, add-to-cart, buy-now, and wishlist actions. ## Map Host Product Routes To Mika Content Refs The URL slug is host-owned. Mika sellable lookup uses a content ref, usually a collection name plus the host entry ID. Resolve the slug to a host product first, then pass the stable content ref to Mika: ```ts const product = productBySlug(Astro.params.slug); const sellablesResult = await Mika.catalog.sellables("products", product.id); ``` Do not assume the route slug and Mika content ID are the same value. The seeded template route `/products/[slug].astro` resolves the slug with `templateProductBySlug(slug)`, then calls `Mika.catalog.sellables("products", product.id)`. The sample below is host-app pseudocode for `src/pages/products/[slug].astro`. ```astro --- import { createMika } from "@bnomei/emdash-mika/astro"; import ProductPurchase from "../../components/ProductPurchase.astro"; import ProductStructuredData from "../../components/ProductStructuredData.astro"; import { productBySlug } from "../../lib/products"; export const prerender = false; const Mika = createMika(Astro); const slug = Astro.params["slug"]; if (!slug) return Astro.redirect("/404"); const product = productBySlug(slug); if (!product) return Astro.redirect("/404"); const sellablesResult = await Mika.catalog.sellables("products", product.id); const sellables = sellablesResult.ok ? sellablesResult.data : []; --- ``` The seeded template uses the same boundary, but its lookup is `templateProductBySlug(slug)` from `src/lib/mika-api.ts` and its route passes fixture overrides with `createMika(Astro, { api: mikaApiOverrides })` so the page reads the resettable template store instead of production repositories. ## Handle Posted Form Results The same page also receives the POST results from the purchase forms. Read them with `Astro.getActionResult()`, and redirect to the provider when a checkout starts: ```astro --- import { actions } from "astro:actions"; const checkout = Astro.getActionResult(actions.mika.checkout.start); if (checkout?.data?.redirectUrl) return Astro.redirect(checkout.data.redirectUrl); const added = Astro.getActionResult(actions.mika.cart.add); // CartDTO on success --- ``` `ProductPurchase` owns the add-to-cart, buy-now, and wishlist forms. It derives its view model with `createMikaPurchaseModel(sellables)` (selected sellable/price, `maxQuantity`, `unavailable`, grouped-variant controls), so you do not hand-assemble those controls. ## Verify - The page renders host product copy and Mika purchase controls from the same content ref. - `ProductStructuredData` receives the same sellables shown to buyers. - Add-to-cart submits to `actions.mika.cart.add` and `Astro.getActionResult()` can render the result. - Checkout start either redirects to a provider session or returns a clear provider/configuration error. Next: use [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) to copy the full action and component set, or use [Cart, Wishlist, And Checkout](https://mika.bnomei.com/guides/cart-wishlist-checkout/) once the product form posts successfully. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/examples/astro-storefront.md` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓐ `../emdash-mika/src/templates/astro/components/ProductStructuredData.astro` - ⓟ `../emdash-mika/src/astro.ts` - ⓣ `../emdash-mika-template/src/pages/products/[slug].astro` - ⓣ `../emdash-mika-template/src/lib/mika-api.ts` - ⓣ `../emdash-mika-template/src/lib/mika-fixture-storefront.ts` # First Integration Checklist Path: /guides/first-integration-checklist/ URL: https://mika.bnomei.com/guides/first-integration-checklist/ Exact host-file checklist for the first Mika integration slice. Use this checklist when starting from an existing Astro + EmDash app. It is the bridge between Getting Started and the deeper implementation guides. Stop after the first product page works. Add cart, wishlist, account, downloads, webhooks, admin actions, and agent metadata only when the host needs those flows. 1. Confirm package state and peer ranges in [Compatibility And Publication](https://mika.bnomei.com/getting-started/compatibility-publication/). 2. Install or link `@bnomei/emdash-mika`, and pin EmDash inside Mika's current peer range. 3. Register EmDash and Mika in `astro.config.mjs`. 4. Create `src/lib/mika-api.ts` with either fixture overrides or a production `createMikaBackendApi()` composition. 5. Copy `templates/astro/actions/index.ts` to `src/actions/index.ts`. 6. Copy `templates/astro/actions/mika.ts` to `src/actions/mika.ts`. 7. Install copied UI dependencies if you copy the Kumo-backed templates. 8. Copy product purchase components plus `src/styles/kumo.css`. 9. Build a host product route that resolves the slug to a stable content ref, then calls `createMika(Astro)`. 10. Add cart, wishlist, account, checkout-return, download, webhook, and metadata pages only when those flows are part of the host app. 11. Run typecheck/build and smoke the browser paths. ## Copy Commands From a host app after a package install, copy from the package export path: ```sh mkdir -p src/actions src/components src/lib src/styles cp node_modules/@bnomei/emdash-mika/src/templates/astro/actions/index.ts src/actions/index.ts cp node_modules/@bnomei/emdash-mika/src/templates/astro/actions/mika.ts src/actions/mika.ts cp node_modules/@bnomei/emdash-mika/src/templates/astro/styles/kumo.css src/styles/kumo.css cp node_modules/@bnomei/emdash-mika/src/templates/astro/lib/routes.ts src/lib/routes.ts cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/ProductPurchase.astro src/components/ProductPurchase.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/ProductPurchaseSync.astro src/components/ProductPurchaseSync.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/AddToCartForm.astro src/components/AddToCartForm.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/AddToCartFormSync.astro src/components/AddToCartFormSync.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/BuyNowForm.astro src/components/BuyNowForm.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/WishlistForm.astro src/components/WishlistForm.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/VariantOptionGroups.astro src/components/VariantOptionGroups.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/VariantSelector.astro src/components/VariantSelector.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/StockBadge.astro src/components/StockBadge.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/LowStockNotice.astro src/components/LowStockNotice.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/UnavailableNotice.astro src/components/UnavailableNotice.astro cp node_modules/@bnomei/emdash-mika/src/templates/astro/components/ProductStructuredData.astro src/components/ProductStructuredData.astro ``` In this local workspace, replace `node_modules/@bnomei/emdash-mika/src/templates/astro` with `../emdash-mika/src/templates/astro` if the package is not installed from npm yet. ## Config Skeleton If you use the Node adapter shown below, run `npm install @astrojs/node`. Otherwise keep the host's existing server adapter import and `adapter` option. ```ts // astro.config.mjs import { defineConfig } from "astro/config"; import node from "@astrojs/node"; // Or keep the host's existing server adapter. import emdash from "emdash/astro"; import { mikaPlugin } from "@bnomei/emdash-mika"; import { api } from "./src/lib/mika-api"; export default defineConfig({ output: "server", adapter: node({ mode: "standalone" }), integrations: [ emdash({ plugins: [mikaPlugin({ api })], }), ], }); ``` Use a native entrypoint (`mikaPlugin({ entrypoint: "#mika-plugin" })`) when `api` is made of local functions or runtime-only modules that should not be serialized through descriptor options. ## Verification Minimum verification for the first slice: - the host build can resolve all copied component imports; - `actions.mika.cart.add` is registered and an add-to-cart form posts without an Action lookup error; - a product page calls `Mika.catalog.sellables(collection, id)` with the host content ref; - `ProductStructuredData` receives the same sellables shown to the buyer; - `/_emdash/api/plugins/mika/catalog/sellables?collection=products&id=` returns a Mika result envelope for a real host content ref; - `/_emdash/api/plugins/mika/sellables/availability?sellableId=` returns availability for a real sellable; - any copied request-bound page exports `prerender = false` or the app uses `output: "server"`. Next: [Product Authoring](https://mika.bnomei.com/guides/product-authoring/) clarifies the content-to-sellable mapping. [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) explains the copied UI and Actions in detail. [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/) explains trusted backend wiring once fixture overrides are not enough. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/actions/index.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/mika.ts` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓐ `../emdash-mika/src/templates/astro/components/ProductStructuredData.astro` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓣ `../emdash-mika-template/astro.config.mjs` - ⓣ `../emdash-mika-template/src/pages/products/[slug].astro` # Product Authoring Path: /guides/product-authoring/ URL: https://mika.bnomei.com/guides/product-authoring/ Map host content entries to Mika sellables, prices, stock, and public metadata. Use this guide when deciding what belongs in EmDash content and what belongs in Mika commerce records. ## The Mapping | Host concept | Mika concept | Notes | | --- | --- | --- | | Product entry | `ContentRefDTO` | Stable `collection`, `id`, optional `locale`. This is the join key; route slugs are host-owned. | | Purchasable format | `SellableDTO` | One product can have multiple sellables for formats, bundles, licenses, subscriptions, or variants. | | Purchase option | `PriceDTO` | Amount in minor units, currency, mode, fulfillment kind, interval fields, and provider refs. | | Stock row | `AvailabilityDTO` / stock repository | Availability is read-time state; the host decides how inventory is stored and reserved. | | Visible product page | JSON-LD + copied purchase components | The page must keep visible content, sellables, price, availability, and structured data in agreement. | ## Example Shape A host product route may use a readable slug while Mika lookup uses a stable content ref: ```ts const product = productBySlug(Astro.params.slug); const sellablesResult = await Mika.catalog.sellables("products", product.id); ``` A matching API response can return sellables such as: ```ts [ { id: "sellable_panel_pack_mira", content: { collection: "products", id: "mira-field-clipboard" }, title: "Mira Panel Pack", active: true, prices: [ { id: "price_panel_pack_mira", amount: 1900, currency: "USD", mode: "one_time", active: true } ], availability: { status: "in_stock", availableQuantity: 24, maxPerOrder: 3 } } ] ``` The exact source DTO carries more fields; this example shows the authoring relationship, not every property. ## Product Page Responsibilities The host product page owns: - slug resolution and 404 behavior; - editorial title, description, media, taxonomy, and layout; - locale handling; - the content ref passed to `Mika.catalog.sellables(...)`; - `ProductStructuredData` props that match visible product state; - route-specific `successPath`, `cancelPath`, and `returnTo` values when defaults do not match copied checkout pages. Mika owns the commerce contracts: - sellable and price DTO shapes; - action field names; - purchase model helpers; - availability snapshots; - JSON-LD template component behavior; - cart/wishlist/checkout operation semantics. ## Seeded Repo Example The seeded template uses `seed/mika-actions.seed.json` as fixture data and `src/lib/mika-fixture-storefront.ts` as resettable behavior. It proves product authoring shapes, but it is not Mika's product editor or production schema. Do not copy fixture IDs, readable download tokens, or in-memory behavior into production. Copy the mapping pattern: content entry to content ref to sellable to price to stock. ## Verify - The host content entry resolves to a stable collection/id pair before calling `Mika.catalog.sellables(...)`. - Visible product title, description, price, availability, and variants match the sellables passed to `ProductStructuredData`. - Unavailable or low-stock state is visible in the purchase UI before the buyer submits a form. Next: [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) copies the action and component set. If you have not built a product route yet, use [First Product Page](https://mika.bnomei.com/getting-started/first-product-page/) first. [Product JSON-LD](https://mika.bnomei.com/examples/product-jsonld/) shows the structured-data copy path. ## Source Anchors - ⓟ `../emdash-mika/src/api/types.ts` - ⓟ `../emdash-mika/src/types/documents.ts` - ⓟ `../emdash-mika/src/model/builders.ts` - ⓐ `../emdash-mika/src/templates/astro/components/ProductStructuredData.astro` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓣ `../emdash-mika-template/seed/mika-actions.seed.json` - ⓣ `../emdash-mika-template/src/pages/products/[slug].astro` - ⓣ `../emdash-mika-template/src/lib/mika-fixture-storefront.ts` # Astro Storefront Path: /guides/astro-storefront/ URL: https://mika.bnomei.com/guides/astro-storefront/ Copy Mika Actions, components, and pages into a host Astro storefront. Use this guide when building the browser storefront. Start here after the plugin is registered and one product page can call `createMika(Astro)`. Mika's default storefront path is Astro-native: - HTML forms submit to `actions.mika.*`. - Product pages use `createMika(Astro)`. - The host app owns routes, content, layout, localization, auth policy, provider credentials, and deployment. - Copied components use Kumo-backed UI patterns but remain ordinary host files. ## Prerequisites - Mika is installed or linked as described in [Install](https://mika.bnomei.com/getting-started/install/). - `mikaPlugin({ api })` or a native `entrypoint` is registered in `astro.config.mjs`. - The host can provide fixture overrides or a real `MikaApi` implementation. - The app can run dynamic routes with `output: "server"` or per-route `prerender = false`. ## Storefront Checklist 1. Copy the action files and product components. 2. Install UI dependencies if you use the Kumo-backed templates. 3. Register `server.mika = createMikaActions()`. 4. Render product purchase forms from `createMika(Astro)` sellables. 5. Add host guards for rate limits, account policy, and feature gates. 6. Verify that only catalog and stock reads are public plugin JSON routes. ## Core Copy Path Copy the action files and product components first: ```txt src/actions/index.ts src/actions/mika.ts src/styles/kumo.css src/lib/routes.ts src/components/MikaKumoAppFrame.tsx src/components/MikaKumoPage.astro src/components/ProductPurchase.astro src/components/ProductPurchaseSync.astro src/components/AddToCartForm.astro src/components/AddToCartFormSync.astro src/components/BuyNowForm.astro src/components/WishlistForm.astro src/components/VariantOptionGroups.astro src/components/VariantSelector.astro src/components/StockBadge.astro src/components/LowStockNotice.astro src/components/UnavailableNotice.astro src/components/ProductStructuredData.astro ``` Add cart, wishlist, checkout, account, downloads, and webhooks only when the host project needs those flows. `src/lib/routes.ts` is included because `BuyNowForm.astro` uses template checkout defaults (`/checkout/success` and `/checkout/cancel`). If the host does not copy those checkout return pages yet, either copy them with the full storefront flow or pass host-owned `successPath` and `cancelPath` props when rendering `BuyNowForm` / `ProductPurchase`. ## UI Dependencies For Copied Templates The copied components use Kumo components, Phosphor icons, and a React island for the app frame. Add these in the host app when copying the template UI: ```sh npm install @cloudflare/kumo @phosphor-icons/react react react-dom @astrojs/react ``` Add `react()` to the host's existing `integrations` array; keep `emdash(...)` and any other integrations already present: ```ts import react from "@astrojs/react"; export default defineConfig({ integrations: [ react(), // Keep the host's existing integrations here. ], }); ``` Copy `src/styles/kumo.css` or import it from your app stylesheet. The UI dependencies belong to the template presentation layer; Mika's package contracts still remain provider- and layout-neutral. `MikaKumoPage.astro` imports `../styles/kumo.css` relative to `src/components/`, so the default destination is `src/styles/kumo.css`. If you move either file, update that import. ## Register The Actions Copied forms post to `actions.mika.*`, but that tree exists only once you register it. Copy `src/actions/mika.ts` (a thin re-export that keeps the factory versioned with Mika) and expose it as `server.mika`: ```ts // src/actions/mika.ts export { createMikaActions, mika } from "@bnomei/emdash-mika/astro-actions"; ``` ```ts // src/actions/index.ts import { createMikaActions } from "./mika"; export const server = { mika: createMikaActions() }; ``` When the plugin was registered with `mikaPlugin({ api })`, `createMikaActions()` resolves that same host API by default; pass `createMikaActions({ api })` only to override it. ## Two Call Surfaces Mika exposes the same operations two ways, and copied code picks by context: - **Server reads / resolution** — `const Mika = createMika(Astro)` from `@bnomei/emdash-mika/astro`, in page or endpoint frontmatter (`Mika.cart.get()`, `Mika.catalog.sellables(...)`). Every call returns a result you branch on: `result.ok ? result.data : result.error`. - **Browser mutations** — HTML forms posting to `action={actions.mika.*}` with `method="post"`, read back with `Astro.getActionResult(...)`. There are no public browser JSON mutation routes. Only `catalog.sellables` and `stock.availability` are exposed as public plugin JSON. ## Host Policy With `guard` Mika does not hard-code rate limits, bot checks, or account gates. Add them through the action `guard`, and keep Astro's default `security.checkOrigin` for the CSRF baseline: ```ts // src/actions/index.ts import { ActionError } from "astro:actions"; import { createMikaActions } from "./mika"; export const server = { mika: createMikaActions({ guard: async (ctx, action, input) => { if (await isRateLimited(ctx)) { throw new ActionError({ code: "TOO_MANY_REQUESTS", message: "Slow down." }); } }, }), }; ``` Keep `src/actions/mika.ts` as the thin re-export from the copyable template file. Put host-specific policy in `src/actions/index.ts`, where the host creates the `server.mika` action tree: ```ts // src/actions/mika.ts export { createMikaActions, mika } from "@bnomei/emdash-mika/astro-actions"; ``` For production, replace `isRateLimited(ctx)` with host code, for example: ```ts async function isRateLimited(ctx: unknown): Promise { // Check the host rate-limit store, bot score, account state, or feature flag. return false; } ``` If a guard needs the operation name, use the `action` argument to branch: ```ts guard: async (ctx, action, input) => { if (action === "checkoutStart" && await checkoutBlocked(ctx, input)) { throw new ActionError({ code: "FORBIDDEN", message: "Checkout is not available." }); }, }, ``` ## Verify - `actions.mika.cart.add` exists and an add-to-cart form posts without an Action lookup error. - `Astro.getActionResult(actions.mika.cart.add)` can render success or failure feedback. - `/_emdash/api/plugins/mika/catalog/sellables?collection=products&id=` returns a Mika result envelope for a real host content ref. - `/_emdash/api/plugins/mika/sellables/availability?sellableId=` returns availability for a real sellable. - Cart, checkout, account, webhook, admin, and agent-tool mutations are not exposed as public plugin JSON routes. Next: [Cart, Wishlist, And Checkout](https://mika.bnomei.com/guides/cart-wishlist-checkout/) covers buyer state and checkout forms. Revisit [Product Authoring](https://mika.bnomei.com/guides/product-authoring/) if sellable, price, stock, or JSON-LD mapping still feels unclear. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/examples/astro-storefront.md` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/actions/index.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/mika.ts` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓐ `../emdash-mika/src/templates/astro/components/AddToCartForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/BuyNowForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/MikaKumoPage.astro` - ⓐ `../emdash-mika/src/templates/astro/lib/routes.ts` - ⓟ `../emdash-mika/src/astro-actions.ts` # Cart, Wishlist, And Checkout Path: /guides/cart-wishlist-checkout/ URL: https://mika.bnomei.com/guides/cart-wishlist-checkout/ Browser mutation flows through Astro Actions and passive checkout returns. Use this guide for browser-facing buyer flows after product purchase forms post successfully. Mika exposes form-first Astro Actions for cart, wishlist, coupon, and checkout start flows. These are the default browser mutation surface. Do not expose cart, checkout, account, subscription, webhook, or admin mutation routes as public JSON endpoints unless the host has implemented the matching auth, CSRF, confirmation, idempotency, rate-limit, and provider policy. ## Task Map | Task | Start with | Verify | | --- | --- | --- | | Add a product to cart | `actions.mika.cart.add` | The cart page shows the new line or a visible validation error. | | Edit a cart | `cart.update`, `cart.remove`, `cart.applyCoupon`, `cart.removeCoupon` | `Mika.cart.get()` returns the updated totals. | | Start checkout | `actions.mika.checkout.start` | The posted page redirects to `checkout.data.redirectUrl` or shows a provider/config error. | | Save to wishlist | `wishlist.add`, `wishlist.moveToCart`, `wishlist.remove` | `Mika.wishlist.get()` reflects the change. | ## Add To Cart An add-to-cart control is an HTML form posting to the `cart.add` action. The ⓐ copyable `AddToCartForm.astro` wraps this in Kumo UI; the Mika contract is the action plus its fields: ```astro --- import { actions } from "astro:actions"; import { mikaHiddenInput, mikaReturnToInput } from "@bnomei/emdash-mika/astro"; const { sellableId, priceId, maxQuantity = 99, returnTo } = Astro.props; ---
``` `mikaHiddenInput` / `mikaReturnToInput` come from `@bnomei/emdash-mika/astro`, not a required copied `src/lib/form.ts`. `mikaHiddenInput` serializes name/value pairs; `mikaReturnToInput` runs `mikaSafeReturnTo`, so a posted `returnTo` can never become an open redirect. On the grouped-variant path the form posts a single serialized `purchase` field instead of discrete `sellableId` / `priceId` — `ProductPurchase` decides which. ## Action Result UX Astro Actions return structured results. Copied pages should branch on the action result before rendering stale state: ```astro --- const added = Astro.getActionResult(actions.mika.cart.add); const failed = added?.error; const message = failed ? failed.message : added?.data ? "Added to cart." : undefined; --- ``` Use `result.ok` envelopes from `createMika(Astro)` for server reads and Astro Action results for posted forms. Do not silently ignore failed action results; show the host's validation or provider message where the buyer can act on it. ## Cart Page Read the cart with the request-bound helper, and redirect first when a checkout start returned a provider URL: ```astro --- import { createMika } from "@bnomei/emdash-mika/astro"; import { actions } from "astro:actions"; export const prerender = false; const Mika = createMika(Astro); const checkout = Astro.getActionResult(actions.mika.checkout.start); if (checkout?.data?.redirectUrl) return Astro.redirect(checkout.data.redirectUrl); const cartResult = await Mika.cart.get(); const cart = cartResult.ok ? cartResult.data : null; --- ``` Copied cart, wishlist, checkout success, and checkout cancel pages export `prerender = false` because they read request state, action results, sessions, and provider-backed checkout status. Each line is edited by its own form: `cart.update` (fields `lineId`, `quantity`), `cart.remove` (`lineId`), and `wishlist.saveForLater` (`lineId`) to move a line to the wishlist. Render amounts with `formatMikaMoney(...)` from `@bnomei/emdash-mika/astro` — money is in minor units. ## Coupons ```astro
``` `cart.removeCoupon` (field `cartId`) clears it. Tax and shipping are display-only fields on the cart DTO — Mika is not a tax or shipping engine. ## Checkout Checkout starts from a form (a cart checkout posts `cartId`; a buy-now posts `sellableId` / `priceId` / `quantity`), always with sanitized redirect fields built by `mikaRedirectInputs`: ```astro --- import { mikaHiddenInput, mikaRedirectInputs } from "@bnomei/emdash-mika/astro"; const { successPath = "/checkout/success", cancelPath = "/checkout/cancel", returnTo = "/cart", } = Astro.props; const redirect = mikaRedirectInputs( { successPath, cancelPath, returnTo }, { successFallback: "/checkout/success", cancelFallback: "/checkout/cancel", returnToFallback: "/cart", }, ); ---
``` `mikaRedirectInputs()` sanitizes each posted path and uses caller-provided fallbacks. The ⓐ copyable checkout components pass `mikaTemplateRoutes.checkoutSuccess` and `mikaTemplateRoutes.checkoutCancel`; host apps can pass their own route constants. The page redirects to `checkout.data.redirectUrl` (see the cart frontmatter above). On return, `/checkout/success` expects `checkoutId` and optional `token` query params, then reads `Mika.checkout.status({ checkoutId, token })` and maps the status (`pending`, `completed`, `cancelled`, `expired`, `failed`, `binding_mismatch`) to a message. ## Wishlist `wishlist.add` (fields `sellableId`, `priceId`, `returnTo`) adds an item. The wishlist page reads `Mika.wishlist.get()`, and each row posts `wishlist.moveToCart` or `wishlist.remove` (field `itemId`). ## Checkout Return Rule Checkout success and cancel pages are browser return surfaces. Success must confirm payment/order state through provider-backed APIs and Mika status tokens. Cancel may call `Mika.checkout.cancel({ checkoutId, token })` to abandon a checkout and preserve cart UX, but it is not payment proof. Expired stock reservation cleanup still belongs to scheduled maintenance, not a cancel page visit. ## Verify - Add-to-cart, cart update, coupon, checkout start, and wishlist forms all render `Astro.getActionResult()` failures where the buyer can act. - Posted redirect fields are created with `mikaRedirectInputs()` or `mikaSafeReturnTo()`. - Copied request-bound pages export `prerender = false` or the app uses server output. - Checkout success validates `checkoutId` and token-bound state through `Mika.checkout.status()`. Next: [Account And Downloads](https://mika.bnomei.com/guides/account-downloads/) covers signed-in customer flows. [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/) covers the trusted API that makes checkout real. ## Source Anchors - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓟ `../emdash-mika/src/api/redirect-policy.ts` - ⓐ `../emdash-mika/src/templates/astro/components/AddToCartForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/CartLines.astro` - ⓐ `../emdash-mika/src/templates/astro/components/CouponForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/CheckoutForm.astro` - ⓟ `../emdash-mika/src/astro.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/cart.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/wishlist.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/checkout/success.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/checkout/cancel.astro` # Account And Downloads Path: /guides/account-downloads/ URL: https://mika.bnomei.com/guides/account-downloads/ Magic-link account flows, orders, subscriptions, licenses, downloads, export, and delete requests. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/pages/account.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/account/orders.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/account/magic-link.astro` - ⓐ `../emdash-mika/src/templates/astro/components/AccountSignInPanel.astro` - ⓐ `../emdash-mika/src/templates/astro/components/MagicLinkForm.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/download/[token].astro` - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/api/types.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓣ `../emdash-mika-template/src/pages/download/[token].astro` - ⓣ `../emdash-mika-template/src/lib/mika-fixture-storefront.ts` - ⓣ `../emdash-mika-template/seed/mika-actions.seed.json` # Backend And Provider Path: /guides/backend-provider/ URL: https://mika.bnomei.com/guides/backend-provider/ Compose the host-owned Mika backend API with repositories, provider adapters, notifications, and maintenance. Use this guide when fixture overrides are no longer enough and the host needs trusted backend behavior. Mika does not ship payment credentials or storage. A host project wires repositories, providers, notification hooks, IDs, hashing, defaults, and checkout config, then passes the resulting API to `mikaPlugin({ api })`. For a production readiness checklist across repositories, idempotency records, provider registry, notifications, and maintenance, see [Production Backend Wiring](https://mika.bnomei.com/guides/production-backend/). If you only need the Stripe webhook endpoint shape, jump to [Stripe And Webhook Cookbook](https://mika.bnomei.com/guides/stripe-webhook-cookbook/). This page is the canonical guide for composing `api`. ## Prerequisites - Mika is installed and registered with EmDash. - The host has chosen fixture overrides or production repositories. - Provider credentials and SDK clients stay in server-only modules. - Notification and maintenance responsibilities are known, even if they are not implemented yet. ```ts import { createMikaBackendApi } from "@bnomei/emdash-mika/server"; import { createMikaProviderRegistry } from "@bnomei/emdash-mika/provider"; export const api = createMikaBackendApi({ repositories, providers: createMikaProviderRegistry([stripeProvider]), notifications: { handle: handleMikaNotification }, defaults, config, createId, now, hash, }); ``` ## Choose A Backend Strategy Use explicit `MikaApiOverrides` when you are writing tests, smoke fixtures, or a narrow custom backend. The seeded template does this: `src/lib/mika-fixture-storefront.ts` supplies fixture storefront behavior, and `src/lib/mika-api.ts` merges in admin/testbed operations. Use `createMikaBackendApi()` for production. It expects durable repository ports for catalog/session/account/ledger/ops/stock/ephemeral behavior, plus provider adapters, notification hooks, IDs, clocks, hashing, defaults, and checkout config. Provider setup is not persistence setup: adding a Stripe provider does not create durable stock, cart, order, webhook, or idempotency storage. ## Descriptor Options Versus Native Entrypoints Passing function-based overrides through `mikaPlugin({ api })` only works when the host's EmDash descriptor path can carry them. If the API is made of local functions, prefer a native entrypoint: ```ts // astro.config.mjs mikaPlugin({ entrypoint: "#mika-plugin" }) ``` The entrypoint module then exports `createPlugin()` and calls Mika's runtime `createPlugin({ api })`. The seeded template's `src/plugins/mika-template-plugin.ts` demonstrates this pattern and shallow-merges template fixture overrides with host options. ## The Host Contract: `MikaApiOverrides` `createMikaBackendApi()` and direct overrides both resolve to one namespaced object — the `MikaApiOverrides` shape. The host implements the methods it needs, and each returns a result envelope: ```ts import type { MikaApiOverrides } from "@bnomei/emdash-mika/server"; // every method returns { ok, status, data } or { ok: false, status, error: { code, message } } const overrides = { catalog: { sellables: (input) => /* ... */ }, // stateless reads: (input) => result cart: { get: (ctx) => /* ... */, add: (ctx, input) => /* ... */ }, // session-scoped: (ctx, input) => result account: { get: (ctx) => /* ... */ }, // wishlist, checkout, magicLink, subscription, download, order, webhook, admin ... } satisfies MikaApiOverrides; ``` The same object feeds `createMikaActions({ api })`, `createMika(Astro, { api })`, and the plugin, so form actions, page reads, and server resolution share one implementation. Stateless reads take `(input)`; session-scoped methods take `(ctx, input)`, where `ctx` exposes `ctx.session` and the resolved customer/session identity. ## Notification Hook Pass a notification hook to deliver email yourself. Return `{ handled: true }` to suppress Mika's default email for that intent (defaults exist for `magic_link.requested` and `order.confirmed`). The [Email And Notifications](https://mika.bnomei.com/reference/email-notifications/) reference lists notification kinds and built-in renderers — map `intent.context.link` to `url` when calling `renderMikaMagicLinkEmail`. ```ts const notifications = { handle: async (intent) => { if (intent.kind === "magic_link.requested") { await sendEmail(intent.context); // toEmail, link, purpose, expiresAt, ... return { handled: true }; } return { handled: false }; }, }; ``` ## Provider Webhook Endpoint Webhooks are host Astro endpoints, not plugin routes. The endpoint forwards the raw `Request` through `createMika(..., { includeWebhook: true })`; Mika's backend reads the raw body from `ctx.request` and calls the registered provider adapter's `verifyWebhook()` and `parseWebhookEvent()`. The `webhook.receive` input is the provider binding plus optional metadata (`eventType`, `payloadHash`, `providerEventId`). `eventType` and `providerEventId` are optional host-supplied fallbacks when the adapter has not parsed them yet — Stripe and most providers supply event metadata from `verifyWebhook()` / `parseWebhookEvent()` instead. ```ts // src/pages/api/mika-webhook/[provider].ts import { createMika } from "@bnomei/emdash-mika/astro"; import { createProviderName } from "@bnomei/emdash-mika/types"; import type { APIRoute } from "astro"; export const prerender = false; export const POST: APIRoute = async ({ params, request, url }) => { const provider = params["provider"]; if (!provider) return new Response("Missing provider.", { status: 400 }); const Mika = createMika({ request, url }, { includeWebhook: true }); // Optional host fallbacks — not provider-native headers. const eventType = request.headers.get("x-event-type"); const providerEventId = request.headers.get("x-provider-event-id"); const result = await Mika.webhook.receive({ provider: createProviderName(provider), ...(eventType ? { eventType } : {}), ...(providerEventId ? { providerEventId } : {}), }); return Response.json(result, { status: result.status }); }; ``` The provider adapter supplies the matching `verifyWebhook()` and `parseWebhookEvent()`. Those methods receive the raw request body that Mika reads from `ctx.request`; the endpoint must preserve the original `Request` for `createMika({ request, url }, { includeWebhook: true })`. The ⓐ copyable Astro webhook endpoint at `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` clones the body to compute host diagnostics (`payloadHash`, `rawBodyLength`, `signatureHeaderPresent`). Mika verification still uses `ctx.request`, and deduplication uses `verified.payloadHash` returned by the provider adapter. Host-side hashing before `webhook.receive` is optional and redundant for verification. ## Verify - `assertMikaApiWired(api, { scope })` passes for the operation families the host exposes. - One catalog read uses the composed API. - One cart or checkout operation returns a real result instead of `NOT_IMPLEMENTED`. - The webhook endpoint preserves the original `Request` until the provider adapter verifies the raw body. Next: [Production Backend Wiring](https://mika.bnomei.com/guides/production-backend/) turns this composition into a readiness checklist. [Provider Contract](https://mika.bnomei.com/reference/provider/) lists the exact adapter methods and capabilities. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/examples/backend-provider.md` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` - ⓟ `../emdash-mika/src/server.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/api/notifications.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓟ `../emdash-mika/src/api/runtime-api.ts` - ⓣ `../emdash-mika-template/src/lib/mika-api.ts` - ⓣ `../emdash-mika-template/src/lib/mika-fixture-storefront.ts` - ⓣ `../emdash-mika-template/src/plugins/mika-template-plugin.ts` # Production Backend Wiring Path: /guides/production-backend/ URL: https://mika.bnomei.com/guides/production-backend/ Durable repository, provider, notification, idempotency, and maintenance requirements for createMikaBackendApi(). Use this page to decide whether a host API is ready to leave fixture mode. ## Prerequisites - Durable storage for catalog, sessions, accounts, ledger/order data, ops/workflow/email/webhook records, stock, and ephemeral records. - A provider registry for the provider behavior the host exposes. - Notification delivery or an explicit decision to use Mika defaults where they exist. - Idempotency storage for protected replay-sensitive operations. - Scheduler access for maintenance tasks. ```ts import { createMikaBackendApi } from "@bnomei/emdash-mika/server"; import { createMikaProviderRegistry } from "@bnomei/emdash-mika/provider"; export const api = createMikaBackendApi({ repositories, providers: createMikaProviderRegistry([stripeProvider]), notifications, defaults, config, createId, now, hash, }); ``` ## Required Dependency Groups | Group | Host responsibility | | --- | --- | | Repositories | Durable catalog, session/cart/wishlist/checkout, account, ledger/order, ops/workflow/email/webhook, stock, and ephemeral storage. | | Provider registry | Registered provider adapters for hosted checkout, portal, invoice, refund, subscription, sync, and webhook behavior the host actually uses. | | IDs and time | Stable `createId`, `now`, optional `isoNow`, and clock behavior for tokens, reservations, workflows, and audit records. | | Hashing | Host-selected hashing for email/customer/account lookup, download tokens, and verification-sensitive records. | | Defaults | Currency, locale, provider, and other defaults that let operations avoid hidden global assumptions. | | Config | TTLs, return paths, magic-link paths, token lifetimes, metadata, and checkout behavior. | | Notifications | A hook that maps Mika intents to host-owned mail/support/ops delivery. | | Maintenance | A scheduled runner plus optional repositories, outbox runner, and ACP session cleanup so email outbox, stuck email leases, raw webhook payload retention, ACP sessions, expired reservations, ephemeral rows, account-delete queues, and stuck workflows are processed. | ## Repository Reality The source repository layer groups state into catalog, session, account, ledger, ops, stock, and ephemeral concerns. A production host does not need to expose those internal storage files as public API, but it does need equivalent durable behavior. Mika can safely replay some workflows only when storage can persist the relevant idempotency and workflow markers. Examples include checkout idempotency, stock reservation idempotency, webhook deduplication, admin audit records, email outbox state, and account-delete requests. ## Provider Is Not Persistence Adding Stripe does not create: - product catalog records; - cart/session persistence; - stock reservations; - order ledger storage; - webhook deduplication records; - email outbox storage; - idempotency records; - tax or shipping rules. The provider adapter only translates provider-facing work. The repositories remain host-owned. ## Verify Production Readiness - `assertMikaApiWired(api, { scope })` passes for the operation families the host exposes. - Checkout start receives a host idempotency key where the calling surface needs replay safety. - Provider webhooks preserve the raw request body until the adapter verifies the signature. - Webhook records are deduplicated by provider event ID or payload hash. - Stock reservations expire through scheduled maintenance; do not rely on users reaching checkout cancel routes. - Account export/delete queues have a maintenance path, and account-delete maintenance can resume recorded cleanup steps after partial failure. - Raw webhook provider payload retention and ACP session cleanup have configured limits or stores when those surfaces are enabled. - Notification hooks either deliver or explicitly allow Mika defaults for supported intents. - Admin runner routes are reachable only through trusted EmDash/admin surfaces. You are ready to leave fixture mode when those checks are true for every route or Action the host exposes. Next: [Stripe Provider](https://mika.bnomei.com/guides/stripe-provider/) wires an optional provider adapter. [Server API](https://mika.bnomei.com/reference/server/) and [Provider Contract](https://mika.bnomei.com/reference/provider/) list the exact backend and adapter contracts. ## Source Anchors - ⓟ `../emdash-mika/src/server.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓟ `../emdash-mika/src/api/server.ts` - ⓟ `../emdash-mika/src/storage/repositories.ts` - ⓟ `../emdash-mika/src/api/maintenance.ts` - ⓟ `../emdash-mika/src/api/email-outbox.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓣ `../emdash-mika-template/src/lib/mika-api.ts` # Stripe Provider Path: /guides/stripe-provider/ URL: https://mika.bnomei.com/guides/stripe-provider/ Wire the optional Stripe provider adapter without making Stripe part of Mika core. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/stripe.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` - ⓐ `../emdash-mika/src/templates/astro/examples/backend-provider.md` # Stripe And Webhook Cookbook Path: /guides/stripe-webhook-cookbook/ URL: https://mika.bnomei.com/guides/stripe-webhook-cookbook/ Secure Stripe adapter wiring, raw-body webhook verification, idempotency, and checkout-return checks. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/stripe.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` - ⓐ `../emdash-mika/src/templates/astro/pages/checkout/success.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/checkout/cancel.astro` # Agent-Ready Commerce Path: /concepts/agent-ready-commerce/ URL: https://mika.bnomei.com/concepts/agent-ready-commerce/ Mika's semantic core for public metadata and host-owned agent protocol projections. Mika is agent-ready because its visible storefront state, operation metadata, and public manifests can agree. Agent-ready does not mean Mika is a hosted agent runtime. Mika does not issue OAuth tokens, run MCP servers, process payment rails, or verify AP2 mandates. The [Glossary](https://mika.bnomei.com/concepts/glossary/) defines the repeated boundary terms used here: public, trusted, admin, hidden, projection, operation descriptor, sellable, content ref, and idempotency key. The semantic core includes catalog, sellables, prices, variants, stock, cart, wishlist, checkout handoff, account, subscription, order, download, provider refs, actor context, proof refs, and idempotency posture. ## What "Agent-Ready" Means Here Agent-ready means the same operation registry can describe: - public storefront facts for crawlers and LLMs; - host-owned trusted flows such as cart quote or checkout preview; - admin-only operations such as stock adjustment or refunds; - hidden service operations such as provider webhooks. The package can produce descriptors and manifests for those semantics. The host still owns the runtime boundary: who may call a tool, how the actor is authenticated, what confirmation is required, how retries are deduplicated, and how provider/payment state is verified. ## Public Manifest Boundary `createMikaAgentManifest()` defaults to the `public` and `trusted` visibility groups. That is useful source material for a protected projection, but it is not automatically safe to publish as a public tool list. The copied `/.well-known/mika-agent.json` endpoint deliberately calls `createMikaAgentManifest({ include: ["public"] })`. That public endpoint should expose route hints for safe catalog and stock reads, plus summaries of protected flows, while leaving checkout, account, order, admin, payment, and tool execution behind host-owned authorization and confirmation. ## Related Tasks - [Agent-Ready Storefront](https://mika.bnomei.com/guides/agent-ready-storefront/) shows the public metadata path. - [LLMs And Manifest](https://mika.bnomei.com/examples/llms-and-manifest/) shows copied metadata endpoints. - [Agent Manifest](https://mika.bnomei.com/reference/agent-manifest/) lists exact manifest helpers and visibility filters. ## Source Anchors - ⓟ `../emdash-mika/docs/agentic/README.md` - ⓟ `../emdash-mika/src/agent.ts` - ⓟ `../emdash-mika/src/api/operation-agent-metadata.ts` - ⓐ `../emdash-mika/src/templates/astro/examples/agent-ready-storefront.md` - ⓐ `../emdash-mika/src/templates/astro/pages/.well-known/mika-agent.json.ts` # Agent-Ready Storefront Path: /guides/agent-ready-storefront/ URL: https://mika.bnomei.com/guides/agent-ready-storefront/ Publish product JSON-LD, llms.txt, and a public Mika agent manifest without exposing protected tools. Use this guide when making a storefront useful to crawlers, LLMs, and shopping agents. ## Prerequisites - Product pages render visible product, price, availability, and variant state. - `ProductStructuredData.astro` is copied or implemented for JSON-LD. - The host can serve root `llms.txt` and `/.well-known/mika-agent.json`. - Protected tool surfaces are not public until host auth, confirmation, idempotency, and provider policy exist. Start with public metadata: - visible HTML product content; - matching `Product` or `ProductGroup` JSON-LD; - accurate price, availability, variants, and seller identity; - root `llms.txt`; - `/.well-known/mika-agent.json` with public descriptors only. Protected agent tools come later. OAuth, policy, confirmations, payment credentials, payment rails, request signatures, webhooks, settlement, tax, shipping, compliance, and final production services are host-owned. ## Public Metadata Checklist - Product HTML, JSON-LD, and visible availability agree. - `llms.txt` describes public reads and protected boundaries. - `/.well-known/mika-agent.json` includes public descriptors only. - Protected cart, checkout, account, admin, and payment flows are summaries, not runnable public tools. - Any ACP, MCP, OpenAPI, UCP, AP2, MPP, or x402 surface is mounted by host-owned infrastructure. ## Public Agent Manifest Serve `/.well-known/mika-agent.json` from the public descriptors only: ```ts // src/pages/.well-known/mika-agent.json.ts import { createMikaAgentManifest } from "@bnomei/emdash-mika/agent"; import type { APIRoute } from "astro"; export const GET: APIRoute = () => Response.json(createMikaAgentManifest({ include: ["public"] })); ``` `createMikaAgentManifest()` is a descriptor source, not a tool server: it does not publish protected mutation routes, validate OAuth, verify AP2 mandates, run MCP, or process payments. Public agent reads are only `catalog.sellables` and `stock.availability`; trusted projections like `cart.quote` and `checkout.preview` stay behind host auth. The ⓐ copyable Astro manifest endpoint also adds `routeBasePath` and `protectedFlowSummaries` to the response. ## Verify Validate the public endpoint with a browser or curl before publishing: ```sh curl http://localhost:4321/.well-known/mika-agent.json curl http://localhost:4321/llms.txt ``` The manifest should list public read routes and summaries of protected flows, not runnable checkout/account/admin tools. ## llms.txt `src/pages/llms.txt.ts` returns a plain-text surface index: the public reads, that browser mutations go through Astro Actions (not JSON routes), and that protected flows need host OAuth, policy, and provider wiring. Keep JSON-LD, `llms.txt`, and the manifest in agreement with the visible catalog. ## Trusted Projections For protected agent integrations, treat Mika descriptors as source material. `cart.quote`, `checkout.preview`, and `order.invoice` are good early candidates because they can be placed behind host auth and confirmation before any payment handoff. Protected protocol projections remain host-owned; Mika only supplies descriptors, ACP helpers, and optional provider adapters. Next: [Product JSON-LD](https://mika.bnomei.com/examples/product-jsonld/) shows the structured-data copy path. [LLMs And Manifest](https://mika.bnomei.com/examples/llms-and-manifest/) shows the public metadata files. [Agent Manifest](https://mika.bnomei.com/reference/agent-manifest/) lists exact manifest helpers. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/examples/agent-ready-storefront.md` - ⓟ `../emdash-mika/src/agent.ts` - ⓟ `../emdash-mika/src/acp.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/.well-known/mika-agent.json.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/llms.txt.ts` # Product JSON-LD Path: /examples/product-jsonld/ URL: https://mika.bnomei.com/examples/product-jsonld/ Structured Product, ProductGroup, and Offer metadata that matches visible storefront state. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/components/ProductStructuredData.astro` - ⓐ `../emdash-mika/src/templates/astro/examples/agent-ready-storefront.md` - ⓣ `../emdash-mika-template/src/pages/products/[slug].astro` # LLMs And Manifest Path: /examples/llms-and-manifest/ URL: https://mika.bnomei.com/examples/llms-and-manifest/ Copyable `llms.txt` and `.well-known/mika-agent.json` public metadata examples. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/pages/llms.txt.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/.well-known/mika-agent.json.ts` - ⓟ `../emdash-mika/src/agent.ts` - `src/pages/llms.txt.ts` - `src/pages/llms-small.txt.ts` - `src/pages/llms-full.txt.ts` # ACP Checkout Path: /guides/acp-checkout/ URL: https://mika.bnomei.com/guides/acp-checkout/ Wire host-owned ACP product-feed and checkout-session endpoints around Mika semantics. Use this guide when building host-owned ACP endpoints around Mika semantics. It focuses on endpoint wiring; exact helper contracts live in [ACP](https://mika.bnomei.com/reference/acp/). ACP helpers live under `@bnomei/emdash-mika/acp`. They serialize Mika catalog and sellable facts into product-feed shapes and expose checkout session handlers for host Astro endpoints. ACP endpoints are host-owned. They need durable session storage with atomic idempotency coordination, official ACP request headers, host auth, and provider-backed order delivery. Do not bake ACP field names into Mika core DTOs. ACP is a projection around Mika semantics. Mika exports `MIKA_ACP_API_VERSION` with value `2025-09-12` and `MIKA_ACP_DEFAULT_SESSION_PREFIX` with value `acp_checkout`. The checkout helper does not mount routes and does not enforce an `API-Version` header by itself; host endpoints that implement OpenAI ACP should validate the official version header before calling the handler. ## Prerequisites - A host `api` object that can quote and start checkout from Mika sellables. - Durable ACP checkout session storage with atomic idempotency claim, bind, and release methods for production. - Host endpoint auth using `Authorization: Bearer ` or the host's chosen signature protection. - Idempotency storage for write endpoints. - Provider-backed order delivery, payment verification, and support policy. ## Minimal Host Shape ACP wiring has two surfaces: 1. A product feed endpoint that serializes Mika catalog/sellable facts. 2. Checkout session endpoints that delegate to `createMikaAcpCheckoutHandlers()`. Mika supplies helpers for those surfaces. The host mounts routes, validates official ACP headers, stores sessions, verifies callers, and handles production payment/provider obligations. ## Product Feed Build an ACP product feed from Mika catalog facts, then serialize it from a host endpoint. Put this in a host-owned Astro endpoint, for example `src/pages/acp/product-feed.json.ts`: ```ts // src/pages/acp/product-feed.json.ts import { createMikaAcpProductFeed, serializeMikaAcpProductFeed } from "@bnomei/emdash-mika/acp"; const feed = createMikaAcpProductFeed({ products: [/* mapped from Mika sellables */] }); export const GET = () => new Response(serializeMikaAcpProductFeed(feed), { headers: { "content-type": "application/json" } }); ``` `serializeMikaAcpProductFeed()` validates the feed before returning JSON and throws with the first invalid path. For file-upload ingestion, use `createMikaAcpFileUploadRows()` and `serializeMikaAcpFileUploadRows()`; those flatten each active sellable/price pair into newline-delimited JSON rows. Structured product-feed prices use Mika minor-unit integer amounts, while file-upload row `price` values are rendered as decimal major-unit strings such as `19.99 USD`. ## Checkout Handlers `createMikaAcpCheckoutHandlers()` returns `create`, `update`, `complete`, `get`, and `cancel` methods for host checkout-session routes. The core ACP checkout flow centers on create, update, and complete; Mika also provides read and cancel handlers for hosts that expose those optional flows. The helper **requires an `apiKey` or `signatureSecret` and throws without one** — knowing a session id must never be enough to read or mutate another buyer's session: ```ts // src/lib/acp-checkout.ts import { createMikaAcpCheckoutHandlers, createMemoryMikaAcpSessionStore, } from "@bnomei/emdash-mika/acp"; export const handlers = createMikaAcpCheckoutHandlers({ api, // the host MikaApi store: createMemoryMikaAcpSessionStore(), // test/demo only — back it with durable storage seller: { /* MikaAcpSeller identity */ }, apiKey: process.env.ACP_API_KEY, // or signatureSecret }); // POST /checkout_sessions -> handlers.create(request) // GET /checkout_sessions/[id] -> handlers.get(request, id) ``` Then import `handlers` from the host Astro endpoints that expose the ACP routes: ```txt src/pages/acp/checkout_sessions/index.ts src/pages/acp/checkout_sessions/[id].ts src/pages/acp/checkout_sessions/[id]/complete.ts src/pages/acp/checkout_sessions/[id]/cancel.ts ``` Each endpoint should be small: read the Astro `request`, call the matching handler, and return the handler response. Example endpoint mapping: ```ts // src/pages/acp/checkout_sessions/index.ts import { handlers } from "../../../lib/acp-checkout"; import type { APIRoute } from "astro"; export const prerender = false; export const POST: APIRoute = ({ request }) => handlers.create(request); ``` ```ts // src/pages/acp/checkout_sessions/[id].ts import { handlers } from "../../../lib/acp-checkout"; import type { APIRoute } from "astro"; export const prerender = false; export const GET: APIRoute = ({ request, params }) => handlers.get(request, params.id!); export const POST: APIRoute = ({ request, params }) => handlers.update(request, params.id!); ``` Write endpoints require an `Idempotency-Key` header. The session store must implement `claimIdempotencyKey`, `bindIdempotencyKey`, and `releaseIdempotencyKey`; Mika coordinates in-progress, replay, and conflict behavior through those atomic methods. The in-memory store is for tests and demos only. ## Headers And Auth Mika's helper supports one or both of these host auth modes: | Option | Required request header | | --- | --- | | `apiKey` | `Authorization: Bearer ` | | `signatureSecret` | `Signature: ` and `Signature-Timestamp` | The `Signature` mode is Mika helper behavior for host-owned protection; it is not a claim that OpenAI's public ACP spec uses that header. Mika signs a canonical payload of uppercase method, pathname plus search, SHA-256 hash of the raw body, and timestamp joined with newlines. The timestamp must parse and fall within Mika's five-minute freshness window. OpenAI ACP integrations should still honor the official `Authorization`, `API-Version`, `Idempotency-Key`, and `Request-Id` expectations at the host endpoint boundary. Body-bearing handlers (`create`, `update`, `complete`, and `cancel`) require `Idempotency-Key`. `get` authenticates but does not require a request body or idempotency key. Handler responses are JSON and echo `Idempotency-Key` and `Request-Id` headers when the request included them. `Accept-Language` is forwarded into the Mika request context. ## Completion Behavior `complete()` serializes completion by session with an internal key shaped like `acp_complete_lock:` so two concurrent completion requests cannot both authorize payment. It currently supports delegated Stripe payment data only: `payment_data.provider` must be `stripe` and `payment_data.token` must be present. Mika stores Stripe delegated-payment metadata before calling `api.checkout.start()`. ## Verify - The feed serializer validates the response and fails with a clear path for invalid product data. - Write endpoints reject missing auth and missing `Idempotency-Key`. - `Request-Id` and `Idempotency-Key` echo when callers provide them. - Completion cannot authorize the same session twice. - Delegated payment data is accepted only for supported provider data. Next: [ACP](https://mika.bnomei.com/reference/acp/) lists exact helper exports. [Agent-Ready Storefront](https://mika.bnomei.com/guides/agent-ready-storefront/) covers the public metadata that should agree with the feed. ## External References - [OpenAI Agentic Commerce](https://developers.openai.com/commerce) for the protocol family this host-owned projection targets. - [OpenAI commerce key concepts](https://developers.openai.com/commerce/guides/key-concepts) for the merchant-of-record and checkout responsibility split. - [OpenAI Checkout Spec](https://developers.openai.com/commerce/specs/checkout) for checkout session endpoint semantics and required request headers. - [OpenAI production guide](https://developers.openai.com/commerce/guides/production) for feed, checkout, and payment integration production considerations. ## Source Anchors - ⓟ `../emdash-mika/src/acp.ts` - ⓐ `../emdash-mika/src/templates/astro/examples/agent-ready-storefront.md` # Deployment Matrix Path: /guides/deployment-matrix/ URL: https://mika.bnomei.com/guides/deployment-matrix/ Node, Cloudflare, GitHub Pages docs, scheduler, storage, and adapter responsibilities. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - `astro.config.mjs` - ⓣ `../emdash-mika-template/astro.config.mjs` - ⓣ `../emdash-mika-template/package.json` - ⓣ `../emdash-mika-template/astro.config.cf.mjs` - ⓣ `../emdash-mika-template/package.cf.json` - ⓣ `../emdash-mika-template/wrangler.cf.jsonc` - ⓣ `../emdash-mika-template/worker.cf.ts` - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/src/api/maintenance.ts` # Deployment And Maintenance Path: /guides/deployment-maintenance/ URL: https://mika.bnomei.com/guides/deployment-maintenance/ Run Mika maintenance, email outbox delivery, webhook payload retention, ACP session cleanup, ephemeral purge, account-delete processing, and lease reclamation. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/src/api/maintenance.ts` - ⓟ `../emdash-mika/src/api/email-outbox.ts` - ⓐ `../emdash-mika/src/templates/astro/examples/backend-provider.md` - ⓣ `../emdash-mika-template/src/plugins/mika-template-plugin.ts` # Cloudflare Variant Path: /guides/cloudflare-variant/ URL: https://mika.bnomei.com/guides/cloudflare-variant/ Optional Worker, D1, and R2 variant files from the seeded GitHub template repo. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓣ `../emdash-mika-template/README.md` - ⓣ `../emdash-mika-template/package.cf.json` - ⓣ `../emdash-mika-template/astro.config.cf.mjs` - ⓣ `../emdash-mika-template/wrangler.cf.jsonc` - ⓣ `../emdash-mika-template/worker.cf.ts` # Admin Actions Path: /guides/admin-actions/ URL: https://mika.bnomei.com/guides/admin-actions/ Expose Mika admin operations through EmDash action provider manifests and field buttons. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/admin.ts` - ⓟ `../emdash-mika/src/api/admin-action-runner.ts` - ⓟ `../emdash-mika/src/api/route-handlers.ts` - ⓣ `../emdash-mika-template/src/emdash/mika-action-fields.ts` - ⓣ `../emdash-mika-template/astro.config.mjs` - ⓣ `../emdash-mika-template/src/pages/api/mika-action-contract.json.ts` - ⓣ `../emdash-mika-template/docs/usage.md` - ⓣ `../emdash-mika-template/seed/mika-actions.seed.json` # Troubleshooting Path: /guides/troubleshooting/ URL: https://mika.bnomei.com/guides/troubleshooting/ Common Mika install, Astro Action, route, provider, and deployment failures. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/src/api/server.ts` - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/stripe.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` - ⓣ `../emdash-mika-template/package.json` # Host-Owned Boundaries Path: /concepts/host-owned-boundaries/ URL: https://mika.bnomei.com/concepts/host-owned-boundaries/ The responsibilities Mika deliberately leaves to the host app. Host ownership is central to Mika's design. Mika provides: - typed commerce DTOs, aggregates, and API contracts; - Astro Actions for browser form submissions; - request-bound helpers for Astro pages and endpoints; - EmDash plugin storage, public catalog/stock JSON routes, and maintenance hooks; - provider adapter interfaces plus optional Stripe adapter helpers; - operation descriptors and agent manifest builders; - copyable Astro templates that become host-owned files after copy. The host owns: - product content and routes; - layout and localization; - auth and session policy; - rate limits and bot checks; - provider credentials and SDK clients; - tax, shipping, compliance, and support; - durable storage and migrations; - payment provider webhooks; - protected agent endpoints and confirmation UX. Mika provides reusable commerce semantics and contracts, not those production responsibilities. The boundary matters most around routes and protocols. Mika's public plugin JSON routes are catalog and stock reads. Cart, wishlist, checkout, account, subscription, webhook, admin, export, delete, and agent-tool mutations flow through host-owned Astro pages, Astro Actions, endpoints, admin actions, or protocol adapters with host policy in front of them. When projecting Mika semantics into ACP, MCP, UCP, OpenAPI, AP2, MPP, x402, OAuth, or another protocol, treat the projection as host infrastructure around Mika contracts. Mika does not become the protocol server or payment rail unless the package source explicitly implements that surface. ## Related Tasks - [Integration File Map](https://mika.bnomei.com/concepts/integration-map/) shows where imported package code, copied files, and seeded examples meet. - [Route Surfaces](https://mika.bnomei.com/concepts/route-surfaces/) explains which browser-visible routes are public reads and which need host policy. - [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/) starts the trusted host wiring path. ## Source Anchors - ⓟ `../emdash-mika/README.md` - ⓟ `../emdash-mika/src/api/routes.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/agent.ts` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/examples/backend-provider.md` # Integration File Map Path: /concepts/integration-map/ URL: https://mika.bnomei.com/concepts/integration-map/ Where Mika, Astro, EmDash, copied templates, and host-owned code meet. Use this page when a code sample says "copy this", "import this", or "register this" and you need to know which runtime owns the file. Mika is not a hidden storefront runtime. An Astro + EmDash host wires the package through ordinary Astro and EmDash files: | File or surface | Owner | What happens there | | --- | --- | --- | | `astro.config.mjs` | Host app | Registers EmDash as an Astro integration, configures EmDash database/storage, and installs `mikaPlugin({ api })`. | | `src/lib/mika-api.ts` | Host app | Builds or exports the host-owned `MikaApi` implementation used by plugin routes, Astro Actions, and request-bound page helpers. | | `src/actions/index.ts` | Host app | Exports Astro's `server` action tree and applies host action policy such as rate limits or account checks. | | `src/actions/mika.ts` | Copied template owned by host after copy | Re-exports `createMikaActions` from `@bnomei/emdash-mika/astro-actions` so copied forms stay aligned with the package version. | | `src/pages/products/[slug].astro` or equivalent | Host app | Loads the host product entry, calls `createMika(Astro)`, reads sellables, and renders copied purchase components. | | `src/components/ProductPurchase.astro` and form components | Copied template owned by host after copy | Render HTML forms that post to `actions.mika.*`; they are not package-owned runtime routes. | | `src/pages/cart.astro`, `src/pages/account.astro`, checkout pages, download endpoint, webhook endpoint | Copied template owned by host after copy | Request-bound pages/endpoints that call `createMika(Astro)` and usually export `prerender = false`. | | `/_emdash/api/plugins/mika/` | EmDash plugin route table from Mika | JSON plugin routes registered by `mikaPlugin`; public reads are limited to catalog sellables and stock availability. | | `/_emdash/admin` | EmDash | Admin UI. Mika can contribute admin action manifests and runner-backed operations, but the admin app is EmDash-owned. | | `src/pages/llms.txt.ts` and `.well-known/mika-agent.json.ts` | Copied template owned by host after copy | Public metadata that describes capabilities and boundaries; it does not grant tool access. | ## Descriptor Options Versus Native Entrypoints `mikaPlugin({ api })` is the short form when the API/options can travel through EmDash's descriptor path in your setup. When the API is function-heavy, or when it needs to merge runtime-only imports, use a native entrypoint instead: ```ts // astro.config.mjs const mikaTemplatePlugin = mikaPlugin({ entrypoint: "#mika-template-plugin" }); ``` The entrypoint module exports `createPlugin()` and calls Mika's runtime `createPlugin({ api })` with local function overrides. The seeded template uses this pattern in `src/plugins/mika-template-plugin.ts` so fixture API functions are imported at runtime instead of serialized through descriptor options. ## Import Versus Copy Import package subpaths when you need contracts or factories: - `@bnomei/emdash-mika` for `mikaPlugin`; - `@bnomei/emdash-mika/astro` for `createMika(Astro)`, money formatting, redirect helpers, and hidden-input helpers; - `@bnomei/emdash-mika/astro-actions` from `src/actions/mika.ts`; - `@bnomei/emdash-mika/server`, `/provider`, `/stripe`, `/admin`, `/agent`, `/acp`, `/email`, and `/types` for their scoped server, provider, admin, metadata, and type contracts. Copy template files when you want host-owned pages and components: - source package path: `../emdash-mika/src/templates/astro/**`; - npm export path: `@bnomei/emdash-mika/templates/astro/*`; - destination in a host Astro app: usually `src/actions/`, `src/components/`, `src/lib/`, `src/pages/`, and `src/styles/`. After copy, those files are yours. Change layout, routes, copy, auth checks, localization, and provider policy in the host app. ## Which API Object Is Used Mika has three common API resolution paths: | Call site | How it finds the API | Boundary | | --- | --- | --- | | `createMika(Astro)` | Uses the default API registered by the active Mika plugin, unless the page passes `createMika(Astro, { api })`. | Server-only Astro page or endpoint helper. | | `createMikaActions()` | Uses the default API registered by the active Mika plugin, unless `createMikaActions({ api })` is passed. | Astro Actions for HTML forms and typed action clients. | | `createMikaClient()` | Calls public plugin JSON reads with `fetch`. | Browser-safe catalog and stock reads only. | The seeded template passes `createMika(Astro, { api: mikaApiOverrides })` on some fixture pages so tests can force local fixture behavior. Production pages normally rely on the plugin-registered API unless they have a clear reason to override it. ## Request Flow Product page flow: 1. Astro routes the request to a host page such as `src/pages/products/[slug].astro`. 2. The page loads the host product entry from EmDash, content collections, or another content source. 3. The page calls `createMika(Astro)` from `@bnomei/emdash-mika/astro`. 4. Mika resolves sellables through the same host API registered with `mikaPlugin({ api })`. 5. Copied components render visible purchase controls and forms that post to `actions.mika.*`. Form mutation flow: 1. A copied form posts to an Astro Action such as `actions.mika.cart.add`. 2. Astro dispatches the action registered in `src/actions/index.ts`. 3. `createMikaActions()` validates the form input and builds a request context from the Astro action context. 4. The operation runs through the host-owned `MikaApi`. 5. The page reads the result with `Astro.getActionResult(...)` and renders feedback or redirects to the checkout provider. Plugin route flow: 1. EmDash serves Mika plugin routes under `/_emdash/api/plugins/mika/`. 2. Mika's operation descriptors map route keys to paths, methods, schemas, public visibility, and agent metadata. 3. Only `catalog/sellables` and `sellables/availability` are public reads. 4. Mutation, account, checkout, webhook, admin, and agent-tool operations need host policy, trusted callers, or copied host endpoints. ## External References - [Astro Actions](https://docs.astro.build/en/guides/actions/) define type-safe backend functions in `src/actions/index.ts` and can be called from HTML form actions. - [Astro on-demand rendering](https://docs.astro.build/en/guides/on-demand-rendering/) explains adapters, `output: "server"`, and per-route `export const prerender = false`. - [EmDash getting started](https://docs.emdashcms.com/getting-started) shows the standard Astro project shape with `astro.config.mjs`, database, and storage configuration. - [EmDash plugin guide](https://docs.emdashcms.com/plugins/creating-plugins/your-first-plugin) describes the descriptor/runtime plugin model Mika registers into. ## Related Tasks - [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) follows the copied Actions and UI path. - [Backend And Provider](https://mika.bnomei.com/guides/backend-provider/) follows the host API and provider path. - [Plugin Routes](https://mika.bnomei.com/reference/plugin-routes/) lists exact plugin route keys and public route rules. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/src/api/routes.ts` - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/api/runtime-api.ts` - ⓟ `../emdash-mika/src/api/client.ts` - ⓟ `../emdash-mika/src/astro.ts` - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/actions/index.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/mika.ts` - ⓣ `../emdash-mika-template/astro.config.mjs` - ⓣ `../emdash-mika-template/src/lib/mika-api.ts` - ⓣ `../emdash-mika-template/src/plugins/mika-template-plugin.ts` # Route Surfaces Path: /concepts/route-surfaces/ URL: https://mika.bnomei.com/concepts/route-surfaces/ Distinguish copied host pages, Astro Actions, EmDash plugin JSON routes, and agent metadata. Mika has separate route surfaces. Treat the word "route" as ambiguous until you know which surface is involved: | Surface | Example | Public browser use | Owner | | --- | --- | --- | --- | | Copied Astro pages | `/cart`, `/wishlist`, `/checkout/success`, `/account` | Yes, as host pages | Host after copy | | Copied provider endpoints | `/api/mika-webhook/[provider]` | No; provider/service caller only with host verification | Host after copy | | Copied download interstitial | `/download/[token]` | Yes, as a host page; POST confirmation consumes the token | Host after copy | | Astro Actions | `actions.mika.cart.add`, `actions.mika.checkout.start` | Yes, through HTML forms | Host action registry using Mika factory | | EmDash plugin JSON routes | `/_emdash/api/plugins/mika/catalog/sellables`, `/_emdash/api/plugins/mika/sellables/availability` | Only safe public reads | Mika plugin inside EmDash | | Public metadata | `/llms.txt`, `/.well-known/mika-agent.json` | Yes, read-only descriptors | Host after copy | | Admin action runner | `/_emdash/api/plugins/mika/.well-known/actions/run` | No | Trusted EmDash/admin flow | The only public plugin JSON reads are: - `catalog.sellables` at route key `catalogSellables`, path `catalog/sellables`, with `collection`, `id`, and optional `locale` search params. - `stock.availability` at route key `sellableAvailability`, path `sellables/availability`, with `sellableId` as the search param. Use Astro Actions for browser mutations by default. ## Wrong Versus Right Wrong for a public browser cart button: ```txt POST /_emdash/api/plugins/mika/cart/items ``` That plugin route is non-public and lacks the host browser policy by itself. Right for the copied storefront: ```astro
...
``` The Astro Action runs behind Astro's action runtime, host guards, and the same Mika API implementation. ## Practical Rule If the browser is changing cart, wishlist, checkout, account, subscription, webhook, admin, export, delete, or agent-tool state, start from an Astro Action or a host-owned protected endpoint. Do not document a plugin JSON path as a public browser mutation route unless the host has added the missing auth, CSRF, confirmation, idempotency, rate-limit, and provider checks. ## HTTP Public Is Not Agent Visibility Mika operation descriptors also carry agent visibility: | Agent visibility | Meaning | | --- | --- | | `public` | Safe public read metadata such as catalog sellables and stock availability. | | `trusted` | Operations a host may project behind auth/session/confirmation policy. | | `admin` | Admin operations for EmDash or other trusted operator surfaces. | | `hidden` | Service/internal operations such as webhook ingestion. | Do not read these labels as a route publication plan. A trusted descriptor can inform a host-owned ACP, MCP, OpenAPI, or custom agent projection, but Mika does not publish those protected tools by itself. ## Related Tasks - [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) uses Astro Actions for browser mutations. - [Security And Idempotency](https://mika.bnomei.com/concepts/security-idempotency/) explains guards, confirmation, and replay boundaries. - [Plugin Routes](https://mika.bnomei.com/reference/plugin-routes/) lists exact public plugin JSON reads. ## External References - [Astro Actions](https://docs.astro.build/en/guides/actions/) for form-backed browser mutations. - [EmDash plugin guide](https://docs.emdashcms.com/plugins/creating-plugins/your-first-plugin) for plugin API route surfaces. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓟ `../emdash-mika/src/api/routes.ts` - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/api/route-handlers.ts` - ⓟ `../emdash-mika/src/api/operation-agent-metadata.ts` # Security And Idempotency Path: /concepts/security-idempotency/ URL: https://mika.bnomei.com/concepts/security-idempotency/ CSRF, action guards, provider signatures, confirmation, and idempotency boundaries. Mika keeps security decisions at the host boundary: browser forms, provider webhooks, admin runners, and agent projections each need different protection. Browser forms should keep Astro's origin checks enabled and add host guards for rate limits, bot checks, account policy, and feature gates. Provider webhooks need raw-body verification through provider adapters. Trusted, admin, and agent runner paths need idempotency where Mika marks it as required. Idempotency records live in host durable storage. Protected agent tools require host-owned auth, confirmation, replay handling, and provider/payment verification. Idempotency keys come from the calling surface. Browser/Action and trusted projections can place them in the `MikaRequestContext`; ACP checkout handlers read the `Idempotency-Key` request header; EmDash admin runner calls read the `Idempotency-Key` header first and otherwise use `invocationId`. Durable records live in host storage: session checkout metadata, stock events, workflow/admin audit rows, webhook records, and ACP session stores. ## Guard And Policy Hooks Use `createMikaActions({ guard })` for host checks that run before an Astro Action calls Mika: rate limits, account/session checks, bot checks, and temporary feature gates. Use `operationPolicy` when the same authorization rule should apply at the operation layer, including plugin routes or trusted runner paths that dispatch through operation descriptors. A policy can allow, forbid, or return a Mika failure envelope. ## Boundary Checklist | Surface | Baseline | | --- | --- | | Astro form actions | Keep Astro's origin check enabled, then add `createMikaActions({ guard })` for host rate limits, account checks, bot checks, and feature gates. | | Provider webhooks | Use a host endpoint and provider adapter verification over the raw request body before accepting payment or subscription state. | | Return paths | Use Mika's same-origin return-path sanitizer for checkout, magic links, and post-auth redirects; it rejects open redirects, protocol-relative URLs, and dot-segment traversal. | | Checkout success | Confirm provider-backed order status through Mika checkout status; do not trust the return URL alone. Checkout start can replay safely when a host idempotency key is present. | | Checkout cancel | Treat as an abandonment/UX surface that may call `checkout.cancel`; do not treat it as payment proof. Release expired stock reservations from scheduled maintenance. | | Admin actions | Run through the trusted EmDash actions runner and require idempotency keys where Mika marks them required. | | Agent/tool projections | Keep host-owned auth, confirmation, replay handling, provider verification, and audit trails outside public metadata endpoints. | Webhook deduplication uses provider evidence, not the browser return URL. Provider adapters verify the raw body and return a `payloadHash`; Mika persists webhook records and uses the provider event ID or payload hash for downstream workflow idempotency. ## Related Tasks - [Astro Storefront](https://mika.bnomei.com/guides/astro-storefront/) shows `createMikaActions({ guard })`. - [Stripe And Webhook Cookbook](https://mika.bnomei.com/guides/stripe-webhook-cookbook/) shows raw-body webhook handling. - [Operations](https://mika.bnomei.com/reference/operations/) lists operation visibility, confirmation, and idempotency metadata. ## External References - [Astro Actions](https://docs.astro.build/en/guides/actions/) for form actions and standardized `ActionError` handling. - [EmDash plugin guide](https://docs.emdashcms.com/plugins/creating-plugins/your-first-plugin) for the plugin API/admin extension surface Mika plugs into. ## Source Anchors - ⓟ `../emdash-mika/src/api/operation-agent-metadata.ts` - ⓟ `../emdash-mika/src/api/operation-policy.ts` - ⓟ `../emdash-mika/src/api/redirect-policy.ts` - ⓟ `../emdash-mika/src/api/route-handlers.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` # Copy Paths Path: /examples/copy-paths/ URL: https://mika.bnomei.com/examples/copy-paths/ Core product, full storefront, and agent-readable copy paths from the core Astro template files. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓐ `../emdash-mika/src/templates/astro/components/AddToCartForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/BuyNowForm.astro` - ⓐ `../emdash-mika/src/templates/astro/lib/routes.ts` - ⓟ `../emdash-mika/package.json` - ⓣ `../emdash-mika-template/src/actions/index.ts` - ⓣ `../emdash-mika-template/src/pages/cart.astro` # Package Exports Path: /reference/package-exports/ URL: https://mika.bnomei.com/reference/package-exports/ Public package subpaths and the role of each exported surface. Use this when choosing imports. Import package subpaths for contracts and factories; copy files only from `@bnomei/emdash-mika/templates/astro/*`. | Subpath | Use this when... | Do not use this for... | | --- | --- | --- | | `@bnomei/emdash-mika` | Registering the native EmDash plugin with `mikaPlugin({ api })`. | Browser code or copied page UI. | | `@bnomei/emdash-mika/acp` | Projecting Mika catalog and checkout semantics into host-owned ACP endpoints. | Claiming Mika ships a hosted ACP server. | | `@bnomei/emdash-mika/agent` | Building public agent manifests or host-owned protocol projections from operation descriptors. | Publishing protected tools without host auth/policy. | | `@bnomei/emdash-mika/admin` | Creating EmDash action provider config and field button options. | Public storefront mutations. | | `@bnomei/emdash-mika/astro` | Astro pages/endpoints that need `createMika(Astro)`, formatting, redirect, hidden-input, or purchase helpers. | Long-lived browser clients. | | `@bnomei/emdash-mika/astro-actions` | `src/actions/mika.ts` and action registration. | Direct route handlers or plugin JSON routes. | | `@bnomei/emdash-mika/client` | Public catalog or stock JSON reads from framework islands. | Protected cart, checkout, account, webhook, admin, or agent-tool mutations. | | `@bnomei/emdash-mika/email` | Built-in email renderer helpers. | Email transport, queues, credentials, or deliverability policy. | | `@bnomei/emdash-mika/provider` | Provider registry and provider-neutral contracts. | A real payment/tax/shipping provider implementation by itself. | | `@bnomei/emdash-mika/react` | Optional React bindings exported by the package. | Astro page routing or provider SDK wiring. | | `@bnomei/emdash-mika/server` | Trusted backend API composition and overrides. | Browser bundles. | | `@bnomei/emdash-mika/stripe` | Optional Stripe provider adapter wiring in server-only host modules. | Making Stripe mandatory or exposing Stripe SDK clients publicly. | | `@bnomei/emdash-mika/types` | DTOs, branded primitives, provider capabilities, and public input/result types. | Internal storage repository imports. | | `@bnomei/emdash-mika/templates/astro/*` | Copying host-owned Astro template files into an app. | Runtime imports for hidden package-owned pages. | Do not import internal `src/api` or `src/storage` modules as public API. See [Client](https://mika.bnomei.com/reference/client/) and [React](https://mika.bnomei.com/reference/react/) for the browser-safe read boundary. ## Root Export Details The root `@bnomei/emdash-mika` export is for EmDash plugin registration and runtime activation: - `mikaPlugin()` builds the static EmDash plugin descriptor for `astro.config.mjs`; - `createPlugin()` is the native runtime entrypoint EmDash activates; - `mika` is an alias for `mikaPlugin`; - `MIKA_PLUGIN_ID`, `MIKA_PLUGIN_VERSION`, and `MIKA_PACKAGE_NAME` identify the plugin and default package entrypoint; - `MIKA_MAINTENANCE_CRON_TASK` and `MIKA_MAINTENANCE_CRON_SCHEDULE` identify the built-in maintenance task; - `MikaDescriptorOptions`, `MikaCreatePluginOptions`, and `MikaMaintenancePluginOptions` type descriptor/runtime options; - `MikaOperationDescriptor` and `MikaOperationPolicy` type operation metadata and host policy hooks. ## Runtime And Peer Ranges - Node engine: `>=22.12.0`. - Astro peer range: `^6.0.0 || ^7.0.0`. - EmDash peer range: `>=0.22.0 <1.0.0`. - Optional peer packages: `@cloudflare/kumo`, `@phosphor-icons/react`, `react`, `react-dom`, and `stripe`. - Published package files are `dist` plus `src/templates`; copyable templates are exposed by `./templates/astro/*`. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓟ `../emdash-mika/src/index.ts` - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/test/package-exports.ts` # Operations Path: /reference/operations/ URL: https://mika.bnomei.com/reference/operations/ Mika operation descriptors for APIs, routes, Actions, policies, and agent manifests. Mika operation descriptors are the internal source of truth for operation names, namespaces, methods, schemas, route metadata, action metadata, public visibility, request-context requirements, and agent metadata. Use the descriptors to look up operation metadata; import public package surfaces instead of internal dispatch helpers. Use this page when you need the exact operation name, route key, route path, Action type, or request-context boundary. Do not use it as a list of browser-callable endpoints: only `public: true` routes are safe public plugin JSON reads. The first two operation families are the only public plugin JSON reads. Everything after `stock.availability` needs an Astro Action, a copied host page, a trusted runner, or a host-owned protected endpoint. Each descriptor carries: | Field | Meaning | | --- | --- | | `namespace` and `method` | The API name, such as `checkout.start`. | | `routeKey` and `routePath` | The EmDash plugin route key and path segment. | | `httpMethod` and `transport` | How plugin-route input is parsed when a host exposes that route. | | `public` | Whether the route can be exposed without session/auth requirements. | | `requiresRequestContext` | Whether the operation receives request/session/locale context. | | `action` | Optional Astro Action client metadata, either `form` or `json`. | | `agent` | Visibility, capability, risk, confirmation, proof, and idempotency metadata. | ## Operation Families | Family | Public plugin JSON route? | Astro Action? | Notes | | --- | --- | --- | --- | | `catalog.sellables` | Yes, `GET catalog/sellables` with `collection`, `id`, `locale` search params. | JSON action. | Public read for content refs. | | `stock.availability` | Yes, `GET sellables/availability` with `sellableId`. | JSON action. | Public read for sellable stock state. | | `cart.*` | No. | Form actions for add/update/remove/merge/coupons; `quote` is operation-only. | Requires request context and host policy. | | `wishlist.*` | No. | Form actions for add/remove/move/save/merge. | Requires request context and host policy. | | `checkout.*` | No. | `start` is a form action; `status` is a JSON action; preview/cancel are operation/plugin route surfaces. | Checkout handoff requires confirmation/payment boundary and idempotency in protected projections. | | `magicLink.*` | No. | Form actions for request/verify. | Host owns auth/session policy and delivery. | | `account.*` | No. | Form actions for export/delete/portal; JSON action for export status. | Export download has separate protected GET/read and POST/consume route operations. Invoice-style reads are protected route/helper surfaces. | | `subscription.*` | No. | Form actions for cancel/change/renew. | Trusted/customer operation family. | | `download.resolve` / `download.confirm` | No. | `download.confirm` is a form action. | `resolve` is the GET/read operation for agents or custom endpoints; `confirm` is the copied interstitial POST that consumes a single-use token after user intent. | | `order.invoice` | No. | No copied Astro Action. | Protected invoice link resolution. | | `webhook.receive` | No. | No copied Astro Action. | Hidden service operation used by host webhook endpoint with provider verification. | | `admin.*` | No. | No storefront Astro Actions. | Trusted EmDash action runner and admin operation family. | The only `public: true` plugin JSON routes are `catalog.sellables` and `stock.availability`. Every mutation, account read, webhook, and admin operation needs host-owned policy before exposure. ## Operation Matrix | Operation | Route key | Plugin route | Public | Request context | Action | | --- | --- | --- | --- | --- | --- | | `catalog.sellables` | `catalogSellables` | `GET catalog/sellables` (`collection`, `id`, `locale`) | Yes | No | `json` | | `stock.availability` | `sellableAvailability` | `GET sellables/availability` (`sellableId`) | Yes | No | `json` | | `cart.get` | `cart` | `GET cart` | No | Yes | `none` | | `cart.quote` | `cartQuote` | `POST cart/quote` | No | Yes | `none` | | `cart.add` | `cartItems` | `POST cart/items` | No | Yes | `form` | | `cart.update` | `cartItem` | `PATCH cart/item` | No | Yes | `form` | | `cart.remove` | `cartItem` | `DELETE cart/item` | No | Yes | `form` | | `cart.merge` | `cartMerge` | `POST cart/merge` | No | Yes | `form` | | `cart.applyCoupon` | `cartCoupon` | `POST cart/coupon` | No | Yes | `form` | | `cart.removeCoupon` | `cartCoupon` | `DELETE cart/coupon` | No | Yes | `form` | | `wishlist.get` | `wishlist` | `GET wishlist` | No | Yes | `none` | | `wishlist.add` | `wishlistItems` | `POST wishlist/items` | No | Yes | `form` | | `wishlist.remove` | `wishlistItem` | `DELETE wishlist/item` | No | Yes | `form` | | `wishlist.moveToCart` | `wishlistMoveToCart` | `POST wishlist/move-to-cart` | No | Yes | `form` | | `wishlist.saveForLater` | `wishlistSaveForLater` | `POST wishlist/save-for-later` | No | Yes | `form` | | `wishlist.merge` | `wishlistMerge` | `POST wishlist/merge` | No | Yes | `form` | | `checkout.start` | `checkout` | `POST checkout` | No | Yes | `form` | | `checkout.preview` | `checkoutPreview` | `POST checkout/preview` | No | Yes | `none` | | `checkout.status` | `checkoutStatus` | `GET checkout/status` (`checkoutId`, `token`) | No | Yes | `json` | | `checkout.cancel` | `checkoutAbandon` | `POST checkout/abandon` | No | Yes | `none` | | `magicLink.request` | `magicLink` | `POST magic-link` | No | Yes | `form` | | `magicLink.verify` | `magicLinkVerify` | `POST magic-link/verify` | No | Yes | `form` | | `account.get` | `account` | `GET account` | No | Yes | `none` | | `account.export` | `accountExport` | `POST account/export` | No | Yes | `form` | | `account.exportStatus` | `accountExportStatus` | `GET account/export/status` (`exportId`) | No | Yes | `json` | | `account.exportDownload` | `accountExportDownload` | `GET account/export/download` (`exportId`, `token`) | No | Yes | `none` | | `account.exportDownloadConsume` | `accountExportDownload` | `POST account/export/download` | No | Yes | `none` | | `account.delete` | `accountDelete` | `POST account/delete` | No | Yes | `form` | | `account.portal` | `accountPortal` | `POST account/portal` | No | Yes | `form` | | `subscription.cancel` | `subscriptionCancel` | `POST subscriptions/cancel` | No | Yes | `form` | | `subscription.change` | `subscriptionChange` | `POST subscriptions/change` | No | Yes | `form` | | `subscription.renew` | `subscriptionRenew` | `POST subscriptions/renew` | No | Yes | `form` | | `download.resolve` | `download` | `GET download` (`token`) | No | No | `none` | | `download.confirm` | `downloadConfirm` | `POST download/confirm` | No | No | `form` | | `order.invoice` | `orderInvoice` | `GET orders/invoice` (`orderId`, `token`, `returnTo`) | No | Yes | `none` | | `webhook.receive` | `webhook` | `POST webhooks` | No | Yes | `none` | | `admin.providerHealth` | `adminProviderHealth` | `POST admin/provider/health` | No | No | `none` | | `admin.providerSync` | `adminProviderSync` | `POST admin/provider/sync` | No | No | `none` | | `admin.stockAdjust` | `adminStockAdjust` | `POST admin/stock/adjust` | No | No | `none` | | `admin.releaseExpiredReservations` | `adminStockReleaseExpiredReservations` | `POST admin/stock/release-expired-reservations` | No | No | `none` | | `admin.webhookReplay` | `adminWebhookReplay` | `POST admin/webhooks/replay` | No | No | `none` | | `admin.orderRefund` | `adminOrderRefund` | `POST admin/orders/refund` | No | No | `none` | | `admin.orderCancel` | `adminOrderCancel` | `POST admin/orders/cancel` | No | No | `none` | | `admin.entitlementGrant` | `adminEntitlementGrant` | `POST admin/entitlements/grant` | No | No | `none` | | `admin.entitlementRevoke` | `adminEntitlementRevoke` | `POST admin/entitlements/revoke` | No | No | `none` | | `admin.emailResend` | `adminEmailResend` | `POST admin/emails/resend` | No | No | `none` | | `admin.licenseRevoke` | `adminLicenseRevoke` | `POST admin/licenses/revoke` | No | No | `none` | | `admin.downloadIssue` | `adminDownloadIssue` | `POST admin/downloads/issue` | No | No | `none` | ## Agent Visibility And Idempotency Mika agent metadata is attached to the same operation descriptors. The preset classes in `operation-agent-metadata.ts` keep these boundaries explicit: | Class | Visibility | Capability pattern | Idempotency | | --- | --- | --- | --- | | Catalog and stock reads | `public` | `catalog:read`, `stock:read` | `not_needed` | | Cart, wishlist, checkout, account, subscription, download, and order flows | `trusted` | Customer or session capabilities | `not_needed`, `recommended`, or `required` depending on effect. | | Provider webhooks | `hidden` | `webhook:receive` | `required` | | Admin reads and writes | `admin` | `admin:read`, `admin:write` | Writes are `required`; reads are `not_needed`. | The idempotency key metadata uses the `Idempotency-Key` header, replay mode `same_key_same_input`, and owner `host`. Mika describes that expectation; the host must persist and enforce it for protected projections. ## Action Tree `src/api/action-tree.ts` derives the `actions.mika.*` namespace tree from descriptors with `action` metadata. The tree is used by `createMikaActions()`; it is not a separate public routing system. ## Source Anchors - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/api/action-tree.ts` - ⓟ `../emdash-mika/src/api/operation-agent-metadata.ts` # Astro Actions Path: /reference/astro-actions/ URL: https://mika.bnomei.com/reference/astro-actions/ `createMikaActions()`, `actions.mika.*`, and typed Mika Astro Actions for form and JSON operations. Use `@bnomei/emdash-mika/astro-actions` from `src/actions/`. Astro expects actions to be exported from a `server` object in `src/actions/index.ts`. Mika's copyable `src/actions/mika.ts` keeps the package import isolated, then `src/actions/index.ts` decides how to expose and guard the tree: ```ts // src/actions/mika.ts export { createMikaActions, mika } from "@bnomei/emdash-mika/astro-actions"; ``` ```ts // src/actions/index.ts import { createMikaActions } from "./mika"; export const server = { mika: createMikaActions(), }; ``` The action tree covers: - catalog sellables; - stock availability; - cart add/update/remove/merge/coupons; - wishlist add/remove/move/save/merge; - checkout start/status; - magic-link request/verify; - account export/delete/portal; - subscription cancel/change/renew. - download confirmation for the copied download interstitial. Use the `guard` option for host policy such as rate limits, auth checks, bot checks, or feature locks. `guard` runs before the selected Astro Action dispatches to Mika. Use it for browser-action concerns tied to Astro's action context. `operationPolicy` runs at the Mika operation layer and is better when the same rule should also apply to plugin routes or trusted runner projections. The package also exports `mika`, a default `createMikaActions()` instance. Copied templates usually call `createMikaActions()` so the host can pass `guard`, `api`, or `operationPolicy` later without changing form components. Common first actions: | Task | Action | | --- | --- | | Add a product to cart | `actions.mika.cart.add` | | Start checkout | `actions.mika.checkout.start` | | Add to wishlist | `actions.mika.wishlist.add` | | Request magic link | `actions.mika.magicLink.request` | | Confirm a download token | `actions.mika.download.confirm` | ## Form Versus JSON Actions Most browser mutations are form actions because copied templates are HTML-first: | Action path | Accept | Returns | | --- | --- | --- | | `actions.mika.catalog.sellables` | `json` | `readonly SellableDTO[]` | | `actions.mika.stock.availability` | `json` | `AvailabilityDTO` | | `actions.mika.cart.add` | `form` | `CartDTO` | | `actions.mika.cart.update` | `form` | `CartDTO` | | `actions.mika.cart.remove` | `form` | `CartDTO` | | `actions.mika.cart.merge` | `form` | `CartDTO` | | `actions.mika.cart.applyCoupon` | `form` | `CartDTO` | | `actions.mika.cart.removeCoupon` | `form` | `CartDTO` | | `actions.mika.wishlist.add` | `form` | `WishlistDTO` | | `actions.mika.wishlist.remove` | `form` | `WishlistDTO` | | `actions.mika.wishlist.moveToCart` | `form` | `CartDTO` | | `actions.mika.wishlist.saveForLater` | `form` | `WishlistDTO` | | `actions.mika.wishlist.merge` | `form` | `WishlistDTO` | | `actions.mika.checkout.start` | `form` | `CheckoutSessionDTO` | | `actions.mika.checkout.status` | `json` | `CheckoutSessionDTO` | | `actions.mika.magicLink.request` | `form` | `{ sent: boolean }` | | `actions.mika.magicLink.verify` | `form` | `AccountDTO` | | `actions.mika.account.export` | `form` | `AccountExportDTO` | | `actions.mika.account.exportStatus` | `json` | `AccountExportDTO` | | `actions.mika.account.delete` | `form` | `{ requested: boolean }` | | `actions.mika.account.portal` | `form` | `{ redirectUrl: string }` | | `actions.mika.subscription.cancel` | `form` | `AccountDTO` | | `actions.mika.subscription.change` | `form` | `AccountDTO` | | `actions.mika.subscription.renew` | `form` | `AccountDTO` | | `actions.mika.download.confirm` | `form` | `DownloadResolutionDTO` | JSON action clients exist for typed read/status calls such as catalog sellables, stock availability, checkout status, and account export status. Do not treat JSON action clients as permission to expose protected browser JSON mutation routes. `actions.mika.download.confirm` is deliberately separate from `download.resolve`. The package template `pages/download/[token].astro` renders a GET interstitial and consumes the single-use token only after a user submits the POST form, so link scanners, previews, and browser prefetch cannot burn the token. ## Error Mapping `createMikaActions()` unwraps `MikaApiResult` envelopes. Successful results become Action data. Failed results become Astro `ActionError` values mapped from HTTP-like status: | Mika status | Astro code | | --- | --- | | `401` | `UNAUTHORIZED` | | `403` | `FORBIDDEN` | | `404` | `NOT_FOUND` | | `409` | `CONFLICT` | | `410` | `GONE` | | `422` | `UNPROCESSABLE_CONTENT` | | `429` | `TOO_MANY_REQUESTS` | | `500` or other `5xx` | `INTERNAL_SERVER_ERROR` | | `501` | `NOT_IMPLEMENTED` | | `503` | `SERVICE_UNAVAILABLE` | | other status values | `BAD_REQUEST` | ## External References - [Astro Actions](https://docs.astro.build/en/guides/actions/) for action registration, form calls, and `Astro.getActionResult()`. - [Astro Actions API reference](https://docs.astro.build/en/reference/modules/astro-actions/) for `defineAction()` and `ActionError`. ## Source Anchors - ⓟ `../emdash-mika/src/astro-actions.ts` - ⓟ `../emdash-mika/src/api/action-tree.ts` - ⓟ `../emdash-mika/src/api/operation-policy.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/mika.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/index.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/download/[token].astro` # Plugin Routes Path: /reference/plugin-routes/ URL: https://mika.bnomei.com/reference/plugin-routes/ EmDash plugin route keys, public route names, and route boundary rules. Mika plugin routes use the EmDash plugin API base: ```txt /_emdash/api/plugins/mika/ ``` Public plugin JSON routes are limited to safe catalog and stock reads: ```txt /_emdash/api/plugins/mika/catalog/sellables /_emdash/api/plugins/mika/sellables/availability ``` Other operation route keys exist in Mika's descriptor table for server/plugin integration, admin runners, trusted clients, and host-owned projections. They are not a browser mutation API just because they have route metadata. Do not document protected plugin route paths as browser mutation APIs. Route URLs are built internally from `EMDASH_PLUGIN_API_BASE` (`/_emdash/api/plugins`), `MIKA_PLUGIN_ID` (`mika`), and the route key map. Public host code should use `createMika(Astro).routes(...)` or `createMikaClient().routes(...)` for the two public reads. Trusted server code can use `createMikaServerClient(...).routes(...)` from `@bnomei/emdash-mika/server` when it needs the full route-key map. Admin action metadata and execution use well-known plugin routes: ```txt /_emdash/api/plugins/mika/.well-known/actions /_emdash/api/plugins/mika/.well-known/actions/run ``` Both are non-public trusted/admin surfaces. ## Route Key Summary Use `createMika(Astro).routes(routeKey, options)` for public route keys in host Astro code. Use `createMikaServerClient(...).routes(routeKey, options)` only from trusted server code that needs non-public route keys. The full operation matrix is in [Operations](https://mika.bnomei.com/reference/operations/). | Route key | Path | Public | Notes | | --- | --- | --- | --- | | `catalogSellables` | `catalog/sellables` | Yes | Public catalog read with `collection`, `id`, and optional `locale`. | | `sellableAvailability` | `sellables/availability` | Yes | Public stock read with `sellableId`. | | `actionsManifest` | `.well-known/actions` | No | EmDash admin action manifest. | | `actionsRunner` | `.well-known/actions/run` | No | EmDash admin action runner. | | Other operation route keys | See [Operations](https://mika.bnomei.com/reference/operations/) | No | Descriptor-backed trusted, admin, webhook, account, cart, checkout, wishlist, subscription, order, and download surfaces. | ## Route Ownership | Need | Preferred surface | | --- | --- | | Product page reads | `createMika(Astro).catalog.sellables(...)` in a host page. | | Browser add/update/remove cart | Astro Actions such as `actions.mika.cart.add`. | | Checkout start | Astro Action `actions.mika.checkout.start`, then redirect to provider URL. | | Provider webhooks | Host endpoint such as `src/pages/api/mika-webhook/[provider].ts`. | | Admin buttons | EmDash actions provider manifest and runner-backed trusted operations. | | Public catalog/stock JSON | The two public plugin JSON reads above. | ## External References - [EmDash plugin guide](https://docs.emdashcms.com/plugins/creating-plugins/your-first-plugin) for the upstream descriptor/runtime plugin model. - [EmDash introduction](https://docs.emdashcms.com/introduction) for the Astro-native host application shape Mika plugs into. ## Source Anchors - ⓟ `../emdash-mika/src/api/routes.ts` - ⓟ `../emdash-mika/src/api/route-handlers.ts` - ⓟ `../emdash-mika/src/api/operations.ts` - ⓟ `../emdash-mika/src/admin.ts` # Server API Path: /reference/server/ URL: https://mika.bnomei.com/reference/server/ `createMikaApi()`, `createMikaBackendApi()`, `createMikaServerClient()`, trusted backend contracts, overrides, and server clients. Use `@bnomei/emdash-mika/server` from trusted backend code. Choose the surface by mode: | Need | Start with | | --- | --- | | Fixture or partial test API | `createMikaApi(overrides)` or direct `MikaApiOverrides` | | Production backend over repositories/providers | `createMikaBackendApi(input)` | | Trusted server-to-plugin HTTP calls | `createMikaServerClient(options)` | Important surfaces include: - `createMikaRequestContext()`; - `MikaRequestContext`; - `MikaSessionAccess`; - `MikaApi`; - `MikaApiOverrides`; - `createMikaApi()`; - `assertMikaApiWired()`; - `mikaApiMethodNames`; - `createMikaBackendApi()`; - `createMikaServerClient()`; - notification hook types; - email outbox and maintenance runners; - operation policy types. Do not expose server APIs directly to browsers. ## API Modes | Mode | Use it when | | --- | --- | | `createMikaApi(overrides)` | You want a partial or test API surface. Missing methods return `501 NOT_IMPLEMENTED`. | | `createMikaBackendApi(input)` | You want a fully wired backend over repositories, providers, ids, hashing, clocks, config, defaults, and notification hooks. | | `createMikaServerClient(options)` | Trusted server code needs to call Mika plugin HTTP routes, including admin and webhook operations. | `assertMikaApiWired(api, { scope })` throws if requested namespaces or fully-qualified methods still point to the not-implemented stub. Use it in host setup or tests to catch missing backend wiring before a route is hit. ## Namespaces `MikaApi` is grouped into these namespaces: - `catalog`; - `stock`; - `cart`; - `wishlist`; - `checkout`; - `magicLink`; - `account`; - `subscription`; - `download`; - `order`; - `webhook`; - `admin`. Methods that mutate session, checkout, account, subscription, order, webhook, or admin state receive a `MikaRequestContext` when request identity matters. ## Request Context `createMikaRequestContext()` normalizes host request data into: - `request`, `url`, and `method`; - actor, scopes, auth subject, and auth issuer; - correlation id and idempotency key; - session id and `MikaSessionAccess`; - customer/user ids; - locale; - `now` as an ISO timestamp. Astro route handlers and Actions normally build this context from the incoming request/session. Backend jobs can also create one explicitly with a synthetic clock, actor, or session id. ## Backend Dependencies `createMikaBackendApi()` expects host-owned infrastructure: - repositories for catalog, session/cart/wishlist/checkout, stock, ledger, account, ops, and other persisted commerce records; - provider registry; - `createId`, `hash`, `now`, and optional `isoNow`; - config for TTLs, success/cancel URLs, magic-link paths, metadata, and token lifetimes; - defaults such as currency, locale, and provider; - optional notification hook. This is the package boundary where Mika becomes a working commerce backend. The package does not create credentials, databases, mail transport, provider accounts, auth, tax rules, or shipping rates for the host. ## Server Client `createMikaServerClient()` builds a fetch-based client over plugin routes. It includes the public browser client operations plus trusted admin and webhook facades, and it exposes a `routes` builder for plugin route URLs. It forwards same-origin cookies from the incoming request by default; use `forwardCrossOriginCookies` only when the host has decided that is safe. ## Source Anchors - ⓟ `../emdash-mika/src/server.ts` - ⓟ `../emdash-mika/src/api/server.ts` - ⓟ `../emdash-mika/src/api/context.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓟ `../emdash-mika/src/api/server-client.ts` - ⓟ `../emdash-mika/src/api/email-outbox.ts` - ⓟ `../emdash-mika/src/api/maintenance.ts` # Provider Contract Path: /reference/provider/ URL: https://mika.bnomei.com/reference/provider/ `MikaProviderAdapter`, `defineMikaProvider()`, `createMikaProviderRegistry()`, and provider adapters for checkout, portal, invoices, refunds, subscriptions, sync, and webhooks. Use `@bnomei/emdash-mika/provider` to define and register payment or commerce provider adapters. Provider adapter means server-only translator: it turns Mika's provider-neutral checkout, portal, invoice, refund, sync, subscription, and webhook contract into calls to a real service such as Stripe, Paddle, Lemon Squeezy, or a custom backend. A complete adapter handles provider-specific checkout sessions, portal sessions, invoice lookup, subscription actions, refunds, catalog sync, webhook verification, and webhook event parsing. ## Core Exports | Export | Role | | --- | --- | | `MikaProviderAdapter` | Interface implemented by a provider adapter. | | `MikaProviderRegistry` | Lookup table keyed by provider name. | | `defineMikaProvider(adapter)` | Identity helper for authoring adapters with type inference. | | `createMikaProviderRegistry(providers)` | Builds the registry consumed by backend APIs. | | `MikaProviderCheckoutInput` | Normalized checkout creation input from Mika cart lines. | | `MikaProviderCheckoutSession` | Normalized provider checkout session returned by create/retrieve. | | `MikaProviderWebhookVerificationInput` | Raw webhook request plus raw body for signature verification. | | `MikaVerifiedWebhookPayload` | Verified raw body, payload hash, headers, and parsed JSON. | | `MikaProviderWebhookEvent` | Payment, subscription, or unknown event normalized for Mika workflows. | | `MIKA_DELEGATED_PAYMENT_TOKEN_METADATA_KEY` | Checkout metadata key carrying an ACP delegated payment token. | | `MIKA_DELEGATED_PAYMENT_PROVIDER_METADATA_KEY` | Checkout metadata key naming the delegated payment provider. | | `MIKA_DELEGATED_PAYMENT_AUTHORIZATION_METADATA_KEY` | Checkout metadata key storing the delegated payment authorization id. | | `MIKA_DELEGATED_PAYMENT_AUTHORIZATION_INPUT_HASH_METADATA_KEY` | Checkout metadata key binding delegated checkout start to the preview authorization input hash. | | `MIKA_DELEGATED_PAYMENT_CHECKOUT_SESSION_ID_METADATA_KEY` | Checkout metadata key linking provider payment back to the ACP checkout session. | ## Adapter Shape Required methods: - `capabilities()`; - `createCheckoutSession(input)`; - `retrieveCheckoutSession(id)`. Optional methods: - `health()`; - `createPortalSession(input)`; - `getInvoiceUrl(input)`; - `cancelSubscription(input)`; - `changeSubscription(input)`; - `renewSubscription(input)`; - `refundPayment(input)`; - `cancelOrder(input)`; - `syncCatalog(input)`; - `verifyWebhook(input)`; - `parseWebhookEvent(input)`. The backend checks provider capabilities before operations that require a specific feature. For optional admin-action methods (`cancelSubscription`, `changeSubscription`, `renewSubscription`, `refundPayment`, `cancelOrder`, `syncCatalog`), unsupported implementations return an `AdminActionResultDTO`. Other optional methods can be omitted or follow their own return contract. ## Capabilities Provider capabilities are exported through the shared types surface: - `hosted_checkout`; - `payments`; - `subscriptions`; - `subscription_renew`; - `subscription_change`; - `subscription_cancel`; - `portal`; - `invoice_url`; - `refunds`; - `coupons`; - `product_sync`; - `variant_sync`; - `stock_sync`; - `webhook_signatures`. `ProviderHealthDTO` reports the provider id, `ok`, capabilities, and optional warnings. ## Checkout Mapping `MikaProviderCheckoutInput` contains the provider name, purchase mode, customer snapshot, cart lines, optional order-level discount, success/cancel URLs, and metadata. Lines carry Mika sellable/price/content references plus optional provider product/price ids. Adapters are responsible for converting those lines into the provider's checkout/session/payment API. `MikaProviderCheckoutSession` returns Mika-normalized status, mode, provider, optional redirect URL, expiration, provider checkout/customer ids, and optional raw provider data. Delegated ACP payment handoff uses provider-neutral metadata keys exported from this subpath. The current key values are `acpPaymentToken`, `acpPaymentProvider`, `acpPaymentAuthorizationId`, `acpPaymentAuthorizationInputHash`, and `acpCheckoutSessionId`. Stripe re-exports provider-specific aliases for the first three keys, but the canonical constants live in `@bnomei/emdash-mika/provider`. ## Webhook Mapping Webhook verification and parsing are split: - `verifyWebhook()` receives the `Request` and raw body, performs provider-specific signature checks, and returns a verified payload plus `payloadHash`; - `parseWebhookEvent()` maps the verified provider payload into `payment`, `subscription`, or `unknown` events. Mika's backend uses normalized payment and subscription events to reconcile orders, entitlements, subscriptions, failures, and webhook replay behavior. The host still owns provider webhook endpoint deployment and provider secret configuration. ## Registry `createMikaProviderRegistry([adapter])` stores adapters by `adapter.id` and exposes `get(provider)` and `list()`. Pass the registry into `createMikaBackendApi()` through backend dependencies. ## Minimal Custom Provider ```ts import { defineMikaProvider } from "@bnomei/emdash-mika/provider"; import { createProviderName } from "@bnomei/emdash-mika/types"; export const customProvider = defineMikaProvider({ id: createProviderName("custom"), async capabilities() { return ["hosted_checkout", "payments"]; }, async createCheckoutSession(input) { return { id: "provider_checkout_123", provider: createProviderName("custom"), status: "pending", mode: input.mode, redirectUrl: "https://provider.example/checkout/provider_checkout_123", }; }, async retrieveCheckoutSession(id) { return { id, provider: createProviderName("custom"), status: "pending", mode: "payment", }; }, }); ``` Add webhook, portal, invoice, refund, subscription, and sync methods only when the provider supports those capabilities and the host has the matching storage, secrets, and policy. ## Stripe Adapter `@bnomei/emdash-mika/stripe` provides an optional Stripe implementation via `createMikaStripeProvider()`. It accepts a host-injected Stripe-shaped client and only advertises capabilities for client surfaces that exist, such as checkout sessions, payment intents, subscriptions, billing portal, invoices, refunds, coupons, catalog sync, and webhook signatures. The Stripe adapter does not create Stripe credentials, tax rules, shipping rates, products, or webhook endpoint configuration. Those remain host-owned. ## Source Anchors - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/api/types.ts` - ⓟ `../emdash-mika/src/api/backend.ts` - ⓟ `../emdash-mika/src/stripe.ts` # Stripe Path: /reference/stripe/ URL: https://mika.bnomei.com/reference/stripe/ Optional Stripe provider adapter and delegated payment metadata keys. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/stripe.ts` - ⓟ `../emdash-mika/src/provider.ts` - ⓟ `../emdash-mika/src/acp.ts` # Astro Template Files Path: /reference/templates/ URL: https://mika.bnomei.com/reference/templates/ Copyable Astro template files, imports, sessions, route shape, and security boundaries. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/package.json` - ⓐ `../emdash-mika/src/templates/astro/README.md` - ⓐ `../emdash-mika/src/templates/astro/actions/index.ts` - ⓐ `../emdash-mika/src/templates/astro/actions/mika.ts` - ⓐ `../emdash-mika/src/templates/astro/lib/routes.ts` - ⓐ `../emdash-mika/src/templates/astro/lib/display.ts` - ⓐ `../emdash-mika/src/templates/astro/lib/cart.ts` - ⓐ `../emdash-mika/src/templates/astro/lib/account.ts` - ⓐ `../emdash-mika/src/templates/astro/components/ProductPurchase.astro` - ⓐ `../emdash-mika/src/templates/astro/components/AddToCartForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/CartSummary.astro` - ⓐ `../emdash-mika/src/templates/astro/components/CheckoutForm.astro` - ⓐ `../emdash-mika/src/templates/astro/components/WishlistList.astro` - ⓐ `../emdash-mika/src/templates/astro/components/AccountDownloads.astro` - ⓐ `../emdash-mika/src/templates/astro/pages/api/mika-webhook/[provider].ts` - ⓐ `../emdash-mika/src/templates/astro/pages/download/[token].astro` - ⓐ `../emdash-mika/src/templates/astro/pages/llms.txt.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/.well-known/mika-agent.json.ts` # Maintenance Path: /reference/maintenance/ URL: https://mika.bnomei.com/reference/maintenance/ Mika maintenance task behavior, cleanup subtasks, and host scheduler responsibilities. Mika registers a maintenance cron task through the EmDash plugin lifecycle. Use this page when wiring or interpreting Mika's `mika_maintenance` cron task. Do not use it as a scheduler guarantee: the host adapter or platform must run EmDash scheduled tasks. The descriptor/runtime split matters: - `mikaPlugin()` writes maintenance options into the EmDash plugin descriptor; - `createPlugin()` registers, cancels, and executes the live cron handler; - `createMikaMaintenanceRunner()` runs one sweep over the configured subtasks. The built-in cron task name is `mika_maintenance`. The default schedule is `* * * * *`, unless the host passes `maintenance.schedule`. The task can: - drain the email outbox; - reclaim exhausted email outbox leases; - purge retained raw webhook provider payloads; - clean up expired ACP checkout sessions; - release expired stock reservations; - purge expired ephemeral rows; - process queued account-delete requests; - reclaim exhausted workflow leases. Each subtask has dependencies. Stock release uses the Mika admin API or a host-provided release function. Email draining requires an `emailOutboxRunner`. ACP session cleanup requires an ACP session store with `cleanupExpired()` or a host-provided cleanup function. Repository-backed cleanup uses the host repositories. Missing dependencies produce skipped task results rather than magically running without host wiring. Host deployments must ensure EmDash scheduled tasks run in the target adapter or platform. In task results, `skipped` usually means the host did not provide the repository or runner that a subtask needs. It is different from `failed`. ## Runtime Inputs | Input | Used by | | --- | --- | | `api` or `releaseExpiredReservations` | Stock reservation release. `createPlugin()` passes the Mika API by default. | | `emailOutboxRunner` | Email outbox delivery. Without it, the email outbox task is skipped. | | `acpSessionStore` or `cleanupExpiredAcpSessions` | ACP checkout-session expiry and terminal-session purge. | | `purgeExpiredEphemeralRecords` | Optional custom expired ephemeral purge. Otherwise repositories can provide it. | | `repositories.ephemeral` | Expired token/session purge and account-delete token cleanup. | | `repositories.ops` | Stuck email reclaim, raw webhook payload purge, account-delete queues, account-delete step recording, email redaction during account delete, and exhausted workflow lease reclamation. | | `repositories.account` | Account-delete subscription checks plus entitlement, license, and customer anonymization. | | `repositories.ledger` | Account-delete order anonymization. | | `repositories.session` | Account-delete active checkout checks. | | `repositories.stock` | Expired stock reservation release and account-delete reservation release. | | `now` | Deterministic clock for the maintenance sweep. | `MikaMaintenanceRunOptions` can override `now`, `emailLimit`, `stuckEmailLimit`, `rawProviderPayloadLimit`, `rawProviderPayloadRetentionDays`, `acpSessionLimit`, `accountDeleteLimit`, and `stuckWorkflowLimit` for one run. ## Task Results `createMikaMaintenanceRunner().runOnce()` returns a `MikaMaintenanceRunResult` with one result per subtask: | Task key | Completed result | | --- | --- | | `emailOutbox` | `MikaEmailOutboxRunResult` counters: `scanned`, `leased`, `sent`, `failed`, `skipped`, `leaseMissed`, `leaseLost`, `hasMore`, plus per-email `items` whose statuses include `lease_missed` and `lease_lost`. | | `stuckEmails` | Counts `scanned` and `reclaimed` exhausted email leases. | | `rawProviderPayloads` | Counts `scanned` and `purged` retained raw webhook payloads older than the retention cutoff. | | `acpSessions` | Counts `scanned`, `expired`, `purged`, and `hasMore` for ACP checkout session cleanup. | | `stockReservations` | Counts scanned reservations, released reservations, and affected stock items. | | `ephemeralRecords` | Count of purged expired ephemeral records. | | `accountDeleteRequests` | Counts scanned, completed, failed, `hasMore`, and per-request items. Completed items include tokens deleted, reservations released, emails redacted, customer anonymization, order anonymization, entitlement anonymization, and license anonymization counts. | | `stuckWorkflows` | Counts scanned and reclaimed exhausted workflow leases. | Each task can be `completed`, `failed`, or `skipped`. The plugin logs a summarized result. Stock reservation failure is rethrown from the cron handler so the host scheduler can observe the failed run. Account-delete processing records each completed cleanup step in request metadata before continuing. If a later step fails after cleanup has started, Mika records the error but leaves the queued request retryable so the next maintenance run can resume completed steps instead of repeating them. ## Host Responsibilities The host must provide durable repositories, an email sender, ACP session cleanup, and retention choices if it expects all maintenance tasks to run. It also owns scheduler execution in production: GitHub Pages does not run cron jobs by itself, and serverless/edge deployments need platform-specific scheduled execution. For EmDash plugin lifecycle background, see the official [EmDash plugin guide](https://docs.emdashcms.com/plugins/creating-plugins/your-first-plugin). ## Source Anchors - ⓟ `../emdash-mika/src/plugin.ts` - ⓟ `../emdash-mika/src/api/maintenance.ts` - ⓟ `../emdash-mika/src/api/email-outbox.ts` # Admin Action Reference Path: /reference/admin-actions/ URL: https://mika.bnomei.com/reference/admin-actions/ Mika admin action manifest, provider config, field button options, and runner-backed action IDs. Summary-only compact entry. Use the page URL above or llms-full.txt for the full procedure. ## Source Anchors - ⓟ `../emdash-mika/src/admin.ts` - ⓟ `../emdash-mika/src/api/admin-action-runner.ts` - ⓣ `../emdash-mika-template/src/emdash/mika-action-fields.ts` - ⓣ `../emdash-mika-template/src/pages/api/mika-action-contract.json.ts` # Agent Manifest Path: /reference/agent-manifest/ URL: https://mika.bnomei.com/reference/agent-manifest/ Mika agent manifest builder, JSON Schema, visibility filters, and operation metadata. Use `@bnomei/emdash-mika/agent` when publishing or projecting Mika operation descriptors. The manifest builder reads Mika's operation descriptors and projects their agent metadata into a JSON document. Public operations include plugin JSON route metadata. Trusted, admin, and hidden operations describe policy expectations but do not become callable public routes by being included in a manifest. Important surfaces include: - `createMikaAgentManifest()`; - `mikaAgentManifestJsonSchema`; - `MIKA_AGENT_MANIFEST_VERSION`; - `MIKA_AGENT_IDEMPOTENCY_KEY_HEADER`; - `MikaAgentActionDescriptor`; - `MikaAgentManifest`; - `MikaAgentOperationMetadata`; - operation visibility, capability, risk, actor, proof, confirmation, and idempotency metadata. By default, `createMikaAgentManifest()` includes `public` and `trusted` operations. The copied public endpoint in the runnable template calls `createMikaAgentManifest({ include: ["public"] })` so `/.well-known/mika-agent.json` advertises only public, read-only route metadata. Use broader includes only behind a host-owned protected tool surface. ## Manifest Shape Each operation descriptor includes: - `name`, `namespace`, and `method` from Mika's operation descriptor; - `public` and `requiresRequestContext` flags; - `agent` metadata, including visibility, capability, scopes, effect, risk, actor requirement, confirmation policy, idempotency policy, resources, and proof kinds; - `route` metadata only for public operations; - `action` metadata when the operation is available through Astro Actions. If `agent.idempotency` is `recommended` or `required`, the metadata includes `idempotencyKey.keyHeader` with the `Idempotency-Key` header and marks the idempotency owner as `host`. ## Visibility Filters | Include value | Use it for | | --- | --- | | `public` | Public manifest and `.well-known/mika-agent.json` metadata. | | `trusted` | Host-owned protected projections after auth, confirmation, idempotency, and provider policy exist. | | `admin` | Operator/admin projections, not storefront metadata. | | `hidden` | Internal/service operations that should not be advertised as tools. | The copied manifest endpoint should stay public-only unless the host has built the protected tool surface separately. ## Copied Endpoint The package template ships `pages/.well-known/mika-agent.json.ts` for hosts to copy into `src/pages/.well-known/mika-agent.json.ts`. After copy, the host owns that Astro API route. It exports `prerender = false` and returns the public manifest, the JSON Schema id, a route base path of `/_emdash/api/plugins/mika`, and short protected-flow summaries for checkout and invoice/account reads. The seeded GitHub template carries the same endpoint as runnable example code. The package also ships `src/templates/astro/pages/llms.txt.ts` and an agent-ready storefront example, but it does not ship a hidden hosted agent server or MCP server. Any ACP, MCP, OpenAPI, UCP, AP2, MPP, or similar protocol surface is a host-owned projection around Mika's operation semantics. ## Source Anchors - ⓟ `../emdash-mika/src/agent.ts` - ⓟ `../emdash-mika/src/api/agent-types.ts` - ⓟ `../emdash-mika/src/api/operation-agent-metadata.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/.well-known/mika-agent.json.ts` - ⓐ `../emdash-mika/src/templates/astro/pages/llms.txt.ts` - ⓐ `../emdash-mika/src/templates/astro/examples/agent-ready-storefront.md` - ⓣ `../emdash-mika-template/src/pages/.well-known/mika-agent.json.ts` # ACP Path: /reference/acp/ URL: https://mika.bnomei.com/reference/acp/ `createMikaAcpCheckoutHandlers()`, `MIKA_ACP_API_VERSION`, and server-only ACP projection helpers for host-owned product feeds, sessions, and order-webhook signing. Use `@bnomei/emdash-mika/acp` for ACP projection helpers. ACP support lives in one server-only package subpath. It maps Mika sellables, cart quotes, checkout previews, and checkout starts into ACP-shaped feeds, session responses, and webhook payloads. It does not register Astro routes by itself; the host chooses where to mount the HTTP handlers and how to protect them. Important surfaces include: - `MIKA_ACP_API_VERSION`; - `MIKA_ACP_DEFAULT_SESSION_PREFIX`; - `createMikaAcpProductFeed()`; - `createMikaAcpFileUploadRows()`; - `serializeMikaAcpFileUploadRows()`; - `serializeMikaAcpProductFeed()`; - `validateMikaAcpProductFeed()`; - `createMikaAcpCheckoutHandlers()`; - `createMemoryMikaAcpSessionStore()`; - `MikaAcpSessionStore`; - `MikaAcpIdempotencyClaim`; - `acpCheckoutSessionFromState()`; - `createMikaAcpOrderWebhookEvent()`; - `signMikaAcpWebhook()`. Production ACP endpoints need official ACP request-header handling, host-owned auth, durable session storage with atomic idempotency coordination, and provider settlement. Do not use this subpath as a hosted ACP server, OAuth issuer, payment rail, or public tool authorization layer. It is a helper layer for host-owned endpoints. `MIKA_ACP_API_VERSION` is currently `2025-09-12`. `MIKA_ACP_DEFAULT_SESSION_PREFIX` is `acp_checkout`. Mika exports handlers, serializers, and stores; it does not register an Astro route tree or enforce an API-version header by itself. ## Feed Helpers | Helper | Role | | --- | --- | | `createMikaAcpProductFeed()` | Projects product inputs plus Mika `SellableDTO` arrays into an ACP product feed with variants derived from active prices. | | `validateMikaAcpProductFeed()` | Checks required product/variant fields, URLs, and non-negative integer price amounts. | | `serializeMikaAcpProductFeed()` | Validates and pretty-prints the feed as JSON. It throws on the first validation issue. | | `createMikaAcpFileUploadRows()` | Flattens active sellable prices into ACP file-upload merchant feed rows with decimal major-unit price strings such as `19.99 USD`. | | `serializeMikaAcpFileUploadRows()` | Serializes file-upload rows as newline-delimited JSON. | Feed input comes from host product pages or EmDash entries plus Mika sellables. The helpers do not crawl the storefront or invent catalog content. Structured `MikaAcpVariant.price.amount` values stay as Mika minor-unit integer amounts. File-upload row `price` values are rendered as decimal major-unit strings with an ISO currency suffix because merchant-feed ingestion expects that format. ## Checkout Handlers `createMikaAcpCheckoutHandlers()` returns five request handlers: | Handler | Role | | --- | --- | | `create(request)` | Creates an ACP checkout session, reconciles cart items, stores session state, and returns a session response. | | `update(request, checkoutSessionId)` | Updates buyer, items, fulfillment address, or fulfillment option before checkout starts. | | `complete(request, checkoutSessionId)` | Validates delegated Stripe payment data, previews checkout, and calls `api.checkout.start()`. | | `get(request, checkoutSessionId)` | Reads stored session state and projects it with current quote/checkout status. | | `cancel(request, checkoutSessionId)` | Cancels stored state and calls `api.checkout.cancel()` when a Mika checkout exists. | The handlers require either `apiKey` or `signatureSecret`. Without one, `createMikaAcpCheckoutHandlers()` throws rather than exposing checkout sessions. If `apiKey` is present, requests must use `Authorization: Bearer `. If `signatureSecret` is present, requests must include Mika's helper-specific `Signature: ` and `Signature-Timestamp` headers. The HMAC payload is canonicalized as uppercase method, pathname plus search, SHA-256 hash of the raw body, and timestamp joined with newlines. The timestamp must parse and be within Mika's five-minute tolerance. Treat that signature mode as host-owned protection around Mika's helper, not as a claim about OpenAI's public ACP request headers. Body-bearing handlers (`create`, `update`, `complete`, and `cancel`) require an `Idempotency-Key` header. `get` authenticates but does not require idempotency. The session store must coordinate retries with `claimIdempotencyKey()`, `bindIdempotencyKey()`, and `releaseIdempotencyKey()`. `createMikaAcpCheckoutHandlers()` asserts those atomic methods before returning handlers. The in-memory store is for development and tests; production hosts need durable storage. Host endpoints that implement OpenAI ACP should validate `API-Version` against `MIKA_ACP_API_VERSION` before dispatching to these handlers; Mika exports the constant but does not enforce the header by itself. The idempotency store key includes request method and pathname. For `create()`, same-key retries replay the originally created session even though the handler mints a fresh candidate session id before claiming the key. For `complete()`, Mika serializes by session with `acp_complete_lock:` so concurrent completion attempts with distinct request keys do not double-authorize payment. ## Session Projection `acpCheckoutSessionFromState()` converts a stored `MikaAcpSessionRecord`, a Mika cart quote, optional checkout status, seller links, and optional order URL into an ACP checkout session response. Status is derived from the checkout status, stored session status, and quote validity. `complete()` currently accepts delegated Stripe payment data only. The body must include `payment_data.token` and `payment_data.provider: "stripe"`. The handler writes Stripe delegated payment metadata into Mika checkout custom fields before calling `api.checkout.start()`. Update and cancel respect terminal state: item changes are rejected after checkout starts, completed sessions cannot be canceled, and canceled sessions cannot be completed or updated. `cancel()` calls `api.checkout.cancel()` for a bound Mika checkout id and ignores provider `404` only. ## Webhook Helpers `createMikaAcpOrderWebhookEvent()` builds `order_created` or `order_updated` payloads containing a checkout session id, permalink URL, status, and refund array. `signMikaAcpWebhook()` returns headers with `-Signature` and `Content-Type: application/json`. The host owns delivery, retry policy, secret storage, settlement verification, and any provider-specific compliance rules. ## External References - [OpenAI Agentic Commerce](https://developers.openai.com/commerce) for the commerce protocol family Mika projects into. - [OpenAI commerce specs](https://developers.openai.com/commerce/specs) for the official Product Feed and Checkout specs. - [OpenAI Checkout Spec](https://developers.openai.com/commerce/specs/checkout) for checkout session endpoint semantics and official request headers. - [OpenAI Products API spec](https://developers.openai.com/commerce/specs/api/products) for product feed API expectations. - [OpenAI production guide](https://developers.openai.com/commerce/guides/production) for production feed, checkout, payment, and compliance considerations. ## Source Anchors - ⓟ `../emdash-mika/src/acp.ts` - ⓟ `../emdash-mika/src/stripe.ts`