Enruta

Docs · Sellers

Accept middleware

LiveUpdated

Sellers. Written for merchants that receive agent orders.

@enruta/accept runs in front of your checkout and answers the question no channel answers for you: this order is from which agent, for whom, under which limit and which policy. It changes nothing about your checkout page, your PSP, your acquirer or your merchant of record, and no money passes through it.

Zero runtime dependencies, Web APIs only (WebCrypto, fetch, Request, Response), so the same code runs on Cloudflare Workers, Vercel Edge, Fastly Compute, Deno and Node 22. Apache-2.0.

Install

import { createAccept, toFetchHandler } from "@enruta/accept";

const accept = createAccept({
  domain: "shop.example",
  sellerKey: env.ENRUTA_SELLER_KEY,      // optional: without it the middleware labels but does not report
});

export default { fetch: toFetchHandler(accept, { origin: "https://origin.shop.example" }) };
OptionDefaultMeaning
domainrequiredYour domain, the payee a mandate must name
sellerKeynoneA seller key (enruta_slr_…) from the console; with it, completed orders are reported and you get a record
enrutaApiUrlhttps://api.enruta.ai
platformProfileUrlhttps://app.enruta.ai/.well-known/agent-profile.jsonWhere the mandate keys are fetched (fallback /.well-known/enruta-keys.json)
cacheTtlSeconds3600Key cache
reporttrue when sellerKey is setReport completed orders to Enruta
enforcefalseWhen true, a complete request with an invalid mandate is answered 402 with the AP2 error code; by default it is passed through labelled X-Enruta-Mandate-Valid: false and your own AP2 check decides
onEvent, fetchAn event sink for logs; a custom fetch

What it does to each request

  1. Recognizes the agent. Signature-Agent (RFC 9421 Web Bot Auth: parsed and reported as signed; the signature itself is not checked in this version), the UCP-Agent header against a fingerprint table (Google, ChatGPT and OpenAI, Copilot, Muse, RyeBot, Enruta, Anthropic), known agent User-Agent substrings, and MCP JSON-RPC bodies.
  2. Verifies the mandate. On POST …/checkout-sessions/{id}/complete and on MCP tools/call with name: "complete_checkout", it reads ap2.checkout_mandate, verifies the ES256 signature against Enruta’s published keys, checks payee === domain, exp in the future and checkout.reference === id. The credential token in the body is left for you; it is never logged or forwarded elsewhere.
  3. Labels the request with the headers below, so your own code can write agent_id + mandate_ref + policy_version into your PSP’s metadata, your order attributes or your risk engine.
  4. Reports the order. When you answer 2xx and the body carries an order, it posts { domain, order, mandate_jws, checkout_id, source: "middleware" } to POST /v0/sellers/orders with your seller key, in the background where the runtime allows (ctx.waitUntil), else with a 3 s timeout, failures ignored. Your response gains X-Enruta-Record when the report finished in time.
HeaderValue
X-Enruta-Agentagt_procurement_02
X-Enruta-Mandatemnd_01M2512M8FQ7ZK4T1V9W3N6BXC
X-Enruta-Policy-Version4
X-Enruta-Principalorg_halvern
X-Enruta-Agent-Platformclaude, chatgpt, google, … or none
X-Enruta-Mandate-Validtrue or false
// accept.inspect(request) → Inspection
{
  agent:   { kind: "ucp" | "web_bot_auth" | "user_agent" | "mcp" | "none", platform: "claude", profile_url: "https://app.enruta.ai/.well-known/agent-profile.json", signed: false },
  mandate: { present: true, valid: true, mandate_id: "mnd_01M2512M8FQ7ZK4T1V9W3N6BXC", agent: "agt_procurement_02",
             policy: { id: "pol_office_supplies", version: 4 }, amount: "24.98", currency: "USD", expires_at: "2026-09-10T17:57:08Z",
             principal_login_id: "halvern/dana.reyes@halvernrobotics.com", reasons: [] }
}

What you get back

With a seller key, every mandated order becomes an agent order on your organization’s chain: labels { agent_id, mandate_ref, policy_version, principal, host }, a risk signal { type: "enruta_mandate_verified", score, metadata { enruta_record, mandate, human_approved, amount_within_mandate, payee_in_mandate } }, the buyer record’s id and hash, and your own sealed record (kind: agent_order, chain: merchant_view_of). When your store signs its orders, the record’s subject is third_party_signed.

POST /v0/sellers/orders           Authorization: Bearer enruta_slr_…
{ "domain": "reamandrule.com", "order": { "id": "ord_01M2512SM3V3A9R4EBJM8RRRV5", … }, "mandate_jws": "eyJ…", "checkout_id": "chk_01M2511XQ4N7B8T2R6H9K3W5MD", "source": "middleware" }

200 {
  "id": "mor_01M2513C4K8Q2W6T9N1B7D5XRH",
  "labels": { "agent_id": "agt_procurement_02", "mandate_ref": "mnd_01M2512M8FQ7ZK4T1V9W3N6BXC", "policy_version": 4, "principal": "org_halvern", "host": "claude" },
  "risk_signals": [{ "type": "enruta_mandate_verified", "score": 0, "metadata": { "enruta_record": "https://api.enruta.ai/v0/records/rec_01M25129GZMJXTNQ47TMZRDGHN", "mandate": "mnd_01M2512M8FQ7ZK4T1V9W3N6BXC", "human_approved": false, "amount_within_mandate": true, "payee_in_mandate": true } }],
  "seller_record_id": "rec_01M2513CJ7W2T9Q4K8N3B6D1XR",
  "buyer_record_id": "rec_01M25129GZMJXTNQ47TMZRDGHN"
}

Seller keys and domains

A seller organization is created in the console (organization type seller); it adds its domains under Settings, and Enruta verifies each by fetching https://<domain>/.well-known/ucp and storing its keys and endpoints. A seller key may only act for verified domains. Orders can also reach Enruta without the middleware: the UCP order webhook order_placed creates the same agent order when the payee has a seller organization, and the middleware’s report is idempotent per order, so both may run.

RoutePurpose
POST /v0/sellers/ordersReport (observe) an agent order; idempotent per (seller, order_id)
GET /v0/sellers/orders, GET /v0/sellers/orders/{id}Your agent orders with labels, risk signals and record ids; filter order_id=
POST /v0/sellers/verify{ mandate_jws, domain, checkout?, amount? }{ valid, claims, reasons[] }: the same check the middleware makes, server-side
GET /v0/sellers/domains, POST /v0/sellers/domainsList and add domains; verification by ucp_keys, dns_txt or manual
GET /v0/sellers/middlewareInstall snippets with your key placeholder, endpoint status, last agent order seen

What is not in this version

  • Verification of the Web Bot Auth signature itself (the header is parsed and reported as signed: true, verified: "not_checked"); Visa TAP and Shopify Signed recognition. Planned.
  • Automatic write-back into your PSP: Stripe PaymentIntent.metadata and Shopify order attributes are planned for October 2026, Adyen and Checkout.com metadata for January 2027. Until then, your code writes the headers where you want them; the Ream & Rule shows the pattern.
  • Braintree, PayPal and Worldpay adapters: 2027.

Pricing: Accept is free, permanently: the middleware, verify_record, record intake for mandated orders, the conformance check and badge, and fulfillment confirmation. The reference merchant at reamandrule.com runs exactly this middleware on its complete and /mcp routes.