Skip to content

ACP

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.

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.

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 <apiKey>. If signatureSecret is present, requests must include Mika’s helper-specific Signature: <base64 hmac-sha256> 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:<checkoutSessionId> so concurrent completion attempts with distinct request keys do not double-authorize payment.

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.

createMikaAcpOrderWebhookEvent() builds order_created or order_updated payloads containing a checkout session id, permalink URL, status, and refund array. signMikaAcpWebhook() returns headers with <merchantName>-Signature and Content-Type: application/json.

The host owns delivery, retry policy, secret storage, settlement verification, and any provider-specific compliance rules.

  • ../emdash-mika/src/acp.ts
  • ../emdash-mika/src/stripe.ts