Backend And Provider
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.
If you only need the Stripe webhook endpoint shape, jump to Stripe And Webhook Cookbook. This page is the canonical guide for composing api.
Prerequisites
Section titled “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.
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
Section titled “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
Section titled “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:
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
Section titled “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:
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
Section titled “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 reference lists notification kinds and built-in renderers — map intent.context.link to url when calling renderMikaMagicLinkEmail.
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
Section titled “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.
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
Section titled “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
Requestuntil the provider adapter verifies the raw body.
Next: Production Backend Wiring turns this composition into a readiness checklist. Provider Contract lists the exact adapter methods and capabilities.
Source Anchors
Section titled “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