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 createMikaPlugin({ api }), createMikaActions({ api }), and request helpers such as createMika(Astro, { 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]), quoteResolver, 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.
Host-Owned Business Quotes
Section titled “Host-Owned Business Quotes”Pass one MikaQuoteResolver as quoteResolver when tax, shipping, or business-specific fees come from host services. The resolver receives Mika’s catalog-priced quote and returns a CartQuoteDTO with authoritative tax, shipping, adjustments, and total values.
Mika reuses that resolver through cart quote, checkout preview, delegated-payment proof, provider handoff, and persisted checkout/order totals. Do not override only cart.quote to add display amounts: that would not make the provider charge the same total. The compile-checked test/fixtures/business-quote-resolver.ts fixture in the package shows a mixed download/external quote using public exports only; the host still owns addresses, rates, carriers, tax services, and policy.
Descriptor Options Versus Native Entrypoints
Section titled “Descriptor Options Versus Native Entrypoints”mikaPlugin() descriptor options are JSON-safe. If the API is made of local functions, repositories, stores, provider SDKs, or policy callbacks, use a native entrypoint:
mikaPlugin({ entrypoint: "#mika-plugin" })The entrypoint module then exports createPlugin() and calls createMikaPlugin({ api }) from @bnomei/emdash-mika/server. 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 createMikaPlugin({ api }), createMikaActions({ api }), and createMika(Astro, { api }), so plugin routes, 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 { createHash } from "node:crypto";import { createMika } from "@bnomei/emdash-mika/astro";import { createProviderName, type WebhookReceiveInput } from "@bnomei/emdash-mika/types";import type { APIRoute } from "astro";import { api } from "../../../lib/mika-api";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 }, { api, includeWebhook: true }); const rawBody = await request.clone().arrayBuffer(); const payloadHash = "sha256:" + createHash("sha256").update(Buffer.from(rawBody)).digest("hex"); const eventType = request.headers.get("x-event-type"); const providerEventId = request.headers.get("x-provider-event-id"); const receiveInput: WebhookReceiveInput = { provider: createProviderName(provider), payloadHash, ...(eventType ? { eventType } : {}), ...(providerEventId ? { providerEventId } : {}), }; const result = await Mika.webhook.receive(receiveInput); 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 a host diagnostic payloadHash and may pass eventType / providerEventId fallbacks. Mika verification still uses ctx.request, and deduplication uses provider evidence such as verified.payloadHash returned by the adapter. Host-side hashing before webhook.receive is optional and redundant for signature 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/backend/quote.ts - ⓟ
../emdash-mika/src/api/backend/checkout/start.ts - ⓟ
../emdash-mika/src/api/server.ts - ⓟ
../emdash-mika/test/fixtures/business-quote-resolver.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