Documentation · API Reference
The MCP tool API
OpenMOM has no REST surface. The entire system — orders, customers, inventory, purchasing, shipping, tax, channels, recurring programs, identity, audit — is exposed as 305 MCP tools across 28 top-level namespaces, so operators, scripts, and AI agents all drive the same validated surface.
The contract
The API is an MCP
server (built on the official @modelcontextprotocol/sdk)
named openmom. Every tool follows the same rules:
- Zod-validated inputs. Each tool's input schema is a strict Zod object, validated before the handler runs — unknown keys are rejected, and the SDK surfaces invalid arguments as
InvalidParams. Nullable columns acceptnull(clearing the value); NOT NULL columns reject explicitnull. - Discriminated results. Tools never throw at the caller. Every result is
{ ok: true, data }or{ ok: false, error: { code, message } }, returned both as JSON text and MCPstructuredContent. - Typed IDs. All identifiers are RFC-4122 UUIDs with compile-time brands (
OrderId,CustomerId, … 61 branded types) — plain UUID strings on the wire, but unmixable in code. - Per-call identity. Every call resolves a caller (
tenantId:userId); the data layer setsapp.tenant_idinside each transaction and Postgres row-level security does the isolation. There are no login tools.
Error codes
| Code | Meaning |
|---|---|
| invalidInput | Schema or semantic validation failure |
| notFound | Entity missing or soft-deleted |
| ambiguous | Lookup matched more than one candidate |
| conflict | Uniqueness violation or illegal state transition |
| unauthorized | No/unknown key, or caller not active for the tenant |
| forbidden | Caller active but lacking the required role |
| tenantNotSet | Request reached the data layer without a tenant context |
| notImplemented | Declared seam not yet wired |
| internal | Unexpected failure (details in server logs, never leaked to callers) |
Authentication
Auth is configured per deployment, not per call session — see
Setup for
the full configuration. In short: static mode pins one
demo caller (OSS default); keys mode authenticates every
call from an API key sent as the x-openmom-api-key header,
an Authorization: Bearer header, or the
openmom_api_key cookie. Every call — in either mode —
re-validates that the caller's tenant, membership, and user are active before touching data,
and every query runs under the openmom_app role with
SET LOCAL app.tenant_id and forced row-level security.
Worked example: orders.create
Creating an order is one atomic call — header, line items, and payments are persisted in a single transaction, the order number is allocated from a per-tenant sequence, and unit prices default server-side from the product catalog when omitted:
{
"customerId": "6a1f2b3c-4d5e-4f60-a718-9b0c1d2e3f40",
"shipVia": "UPS Ground",
"items": [
{ "productId": "a1b2c3d4-e5f6-4a70-8291-3c4d5e6f7a80", "quantity": 2 },
{ "productId": "b9c8d7e6-f5a4-43b2-910f-6e5d4c3b2a19", "quantity": 1, "discountPct": 10 }
],
"payments": [
{
"method": "credit_card",
"amount": "149.9700",
"brand": "visa",
"lastFour": "4242",
"expiryMonth": 12,
"expiryYear": 2028,
"processorToken": "tok_visa_9f8e7d6c5b4a"
}
]
}
The payment union is deliberately tokenized-only: method
selects one of seven payment shapes (credit_card,
ach, check,
cod, invoice_terms,
paypal, gift_card), and the
strict schemas reject a stray PAN- or CVV-shaped key with
invalidInput instead of silently storing it.
The response:
{
"ok": true,
"data": {
"id": "0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f",
"orderNumber": 1042,
"status": "draft",
"customerId": "6a1f2b3c-4d5e-4f60-a718-9b0c1d2e3f40",
"subtotal": "149.9700",
"total": "149.9700",
"lineItems": [
{ "id": "11aa22bb-cc33-4d44-8e55-ff66aa77bb88", "productId": "a1b2c3d4-e5f6-4a70-8291-3c4d5e6f7a80", "quantityOrdered": 2, "unitPrice": "49.9900" },
{ "id": "77aa88bb-cc99-4d00-9e11-22aa33bb44cc", "productId": "b9c8d7e6-f5a4-43b2-910f-6e5d4c3b2a19", "quantityOrdered": 1, "unitPrice": "59.9700", "discountPct": 10 }
]
}
}
Output abridged — IDs and totals illustrative; structure per the orders schema
From there the order walks the same staged pipeline as MOM, with each stage latched by its
own tool so nothing skips ahead:
orders.pick →
orders.pack →
orders.readyToShip →
orders.ship (consumes stock FIFO, backorders short
lines) → orders.invoice, with
orders.hold,
orders.cancel, and the
orders.forceShip escape hatch (audited, doesn't consume
stock) when reality disagrees with the happy path.
Conventions
- IDs — all 61 entity identifiers are UUID strings with compile-time brands (
OrderId,CustomerId, …). No prefixed IDs, no cross-domain type confusion in TypeScript. - Pagination — list tools take
limit(default 50, max 200;audit.listdefaults to 25) and an opaquecursorstring. - Patches — update tools take a partial
patchobject; empty patches are rejected. - Money — monetary inputs and outputs are canonical four-decimal strings such as
"149.9700", never JSON numbers. Inventory and purchasing unit costs retain five decimals. - Soft delete —
deletetools setdeleted_at; deleted entities vanish from get/list but keep their history.
The catalog
Every tool, by domain
305 tools across 28 top-level namespaces. Expand a group for its scope, full tool list, and the
inputs of its key tools — all names and fields copied from the Zod schemas in
packages/api/src/.
orders · 35 tools
Multi-channel order intake, line items, tokenized payments, address and note editing, pick/pack progress, manager stop-point authorizations, and the full staged pipeline (pick → pack → ready → ship → invoice), including quotes, drop-ship PO generation, and refunds.
create · get · list · update · addItem · updateItem · removeItem · addPayment · addNote · hold · cancel · pick · pack · readyToShip · ship · invoice · reconcileShipmentCost · forceShip · saveToQuote · saveFromQuote · processDropShip · recalculateTotalsBatch · capturePayment · refundPayment · updatePayment · removePayment · setAddresses · updateNote · removeNote · setLinePicked · setLinePacked · requestAuthorization · getAuthorization · reviewAuthorization · listAuthorizations
| Tool | Key inputs |
|---|---|
| orders.create | customerId (uuid); billingAddressId, shippingAddressId, soldToAddressId (uuid, optional); header fields — sourceKey, orderType, salesRepMembershipId, shipVia, shipAhead, shippingAmount, taxAmount, otherAmount, holdReason, holdUntil, isQuote, quoteExpiresAt, orderedAt; items[] (productId, quantity, unitPrice?, discountPct?, per-line shipToAddressId/shipVia/shipWhen); payments[] (max 20, see above) |
| orders.list | status?, customerId?, query?, limit (default 50), cursor? |
| orders.hold | reason? / until? — required unless clear: true |
| orders.ship | orderId — consumes on-hand stock FIFO, backorders short lines, re-callable from partial_backorder/backorder |
| orders.refundPayment | orderId, paymentId, amount? (defaults to remaining refundable), reason?, authorizationId?; runtime invoice settlement is refreshed after capture/refund |
| orders.setAddresses | orderId plus billingAddressId, shippingAddressId, soldToAddressId (UUID or null) |
| orders.setLinePicked / setLinePacked | orderLineItemId, quantity — absolute progress during picking/packing |
| orders.requestAuthorization / reviewAuthorization | Maker/checker approval for force_ship, cancel, refund, or hold_release |
| orders.reconcileShipmentCost | lines[] with orderLineItemId, saleTransactionIds[], forcedQuantity, forcedUnitCost? — atomic permission-gated reconciliation of split-line historical COGS provenance |
| orders.forceShip | orderId, reason (required) — escape hatch, audited as a note |
Order status FSM: quote, draft, on_hold, committed, picking, packing, ready_to_ship, shipped, invoiced, plus partial_backorder / backorder and terminal cancelled. Stage tools latch — an order must be committed, and not on hold, before picking.
counterSales · 15 tools
Scanner-first Point-of-Purchase checkout over real OpenMOM orders: tenant-local walk-in policy, product/customer lookup, exact tax and split tenders, concurrency-safe stock consumption, runtime invoices, structured receipts, draft voids, and the existing returns/refund path.
register · create · get · list · scanItem · addItem · updateItem · removeItem · selectCustomer · setTax · addTender · removeTender · complete · void · getReceipt
counterSales.complete is atomic and idempotent: exact applied tenders must equal the order total, cash received records change separately, stock is locked and consumed, the linked order ships and invoices, and a structured receipt is returned. Tender is limited to cash, check, tokenized card, and tokenized gift card.
products · 24 tools
Catalog management: products with kit/breakout bundle components, images, variant attributes, customer-qualified pricing rules, supplier buy prices, and retail price updates that cascade to open orders.
create · get · update · delete · list · addImage · updateImage · deleteImage · addComponent · updateComponent · removeComponent · addPricingRule · updatePricingRule · deletePricingRule · listPricingRules · addAttribute · deleteAttribute · addAttributeValue · deleteAttributeValue · createBuyPrice · updateBuyPrice · deleteBuyPrice · listBuyPrices · updateRetailPrice
Kit components (bundleType: "kit" | "breakout") ship together or break out with their own timing and price overrides. Pricing rules qualify by qty break, source/catalog key, customer type or id, date range, RFM, order type, and web/non-web price level. updateRetailPrice cascades to unshipped open-order lines unless cascadeToOpenOrders: false.
customers · 18 tools
Customer records with per-tenant numbers, addresses (billing / shipping / sold_to / gift_recipient / alternate / contact), tokenized payment methods, contact history, and relationships between customers (bill_to, ship_to, sold_to, gift_recipient, contact).
create · get · update · delete · find · list · addAddress · updateAddress · deleteAddress · addPaymentMethod · deletePaymentMethod · addContact · listContacts · deleteContact · createRelationship · updateRelationship · deleteRelationship · listRelationships
customers.find supports dedupe at intake — exact email/phone matches first, then fuzzy name/company matching. Payment methods store brand, lastFour, expiry, and processorToken — never a PAN.
ncoa · 10 tools
Provider-neutral National Change of Address processing: create a batch, select eligible customer addresses, export a minimized deterministic snapshot, import provider results, review every proposed change, and apply accepted updates with stale-address conflict protection.
createJob · listJobs · getJob · selectAddresses · export · importResults · listResults · reviewResults · applyAccepted · cancel
Job status moves through draft → exported → review → completed, with cancelled terminal. Applying accepted results is transactional and idempotent; changed or deleted source addresses become explicit conflicts instead of being overwritten.
inventory · 19 tools
Warehouses and bins, lot/stock rows with FIFO or FEFO lot methods, signed adjustments, bin transfers, on-hand snapshots, an append-only transaction ledger, and backorder processing.
warehouses.create · warehouses.get · warehouses.update · warehouses.list · bins.create · bins.get · bins.update · bins.delete · bins.list · lots.receive · lots.get · lots.update · lots.list · adjustUnits · adjustLotCost · transfer · stock.get · transactions.list · processUpdates
inventory.adjustUnits takes productId, warehouseId, binId, lotId?, signed adjQty (≠ 0), unitCost?, notation? — every movement appends a ledger row with a running total (receipt / sale / adjustment / transfer / kit_build / kit_break / return).
purchasing · 12 tools
Purchase orders with header/line CRUD, submit, line-by-line or bulk receiving (which creates inventory lots and receipt ledger rows), close, and cancel.
create · get · list · update · addItem · updateItem · removeItem · submit · receiveLine · receiveAll · close · cancel
PO status FSM: draft → submitted → partially_received → received → closed, with cancelled terminal. Receiving writes lots and receipt transactions; drop-ship POs (optionally generated by orders.processDropShip) skip stock.
returns · 7 tools
RMA creation and the requested → authorized → received → processed/cancelled lifecycle, with restock, disposal, exchange links, and optional linked payment refunds.
create · get · list · authorize · markReceived · process · cancel
returns.list reports independent canManage and canAuthorize capabilities; mutation tools still enforce their permissions server-side.
payables · 9 tools
Supplier invoices from received purchase-order quantities, supplier payments, exact-decimal applications, unapplication, and payment voiding.
createInvoiceFromPurchaseOrder · getInvoice · listInvoices · recordPayment · getPayment · listPayments · applyPayment · unapplyPayment · voidPayment
deposits · 5 tools
End-of-day reporting over undeposited captured funds, followed by an atomic batch claim, lookup/list, or void that releases the claimed payments.
report · create · get · list · void
documents · 4 tools
Deterministic structured packing-slip, shipping-label, and invoice payloads plus cursor-paginated generation history. Rendering and browser printing remain caller concerns.
generatePackingSlip · generateShippingLabel · generateInvoice · listGenerations
Generation requires documents.print; history requires documents.view. The history response reports canView and canPrint separately.
vendors · 5 tools
Supplier master records with payment terms and custom fields; deletion is rejected once purchase orders exist — deactivate instead.
create · get · update · delete · list
tax · 12 tools
One tax-jurisdiction model replacing MOM's four parallel tables — national / state / county / zip levels with per-class rates and caps — plus provider configs (Avalara, TaxJar) with secret_ref credentials, a redacted provider call log, and bulk Avalara rate import.
jurisdictions.create · jurisdictions.get · jurisdictions.update · jurisdictions.delete · jurisdictions.list · providers.create · providers.get · providers.update · providers.delete · providers.list · providerTransactions.list · avalara.importRates
shipping · 22 tools
Carriers, one carrier-shipment model replacing a dozen per-carrier manifest tables, provider configs (shippo, shipstation, ups, usps, fedex, dhl) with secret_refs, offline rate bands, and deterministic rate estimates.
carriers.create · carriers.get · carriers.update · carriers.delete · carriers.list · carrierShipments.create · carrierShipments.get · carrierShipments.update · carrierShipments.delete · carrierShipments.list · shipping.providers.create · shipping.providers.get · shipping.providers.update · shipping.providers.delete · shipping.providers.list · shipping.providerTransactions.list · shipping.rateBands.create · shipping.rateBands.get · shipping.rateBands.update · shipping.rateBands.delete · shipping.rateBands.list · shipping.rates.estimate
Shipment status FSM: label_created → shipped → delivered, with voided terminal from any pre-delivered state. shipping.rates.estimate takes weight, zone?, carrierIds? (max 20) and prices from the rate-band matrix — the fallback seam for live provider rate shopping.
channels · 11 tools
Marketplace and storefront connections (amazon, miva, magento, bigcommerce, shopify, salesforce, google_base, shopsite, yahoo, storefront, ebay) with per-listing stock-sync thresholds and a publish state machine (draft → ready → published, error retryable).
connections.create · connections.get · connections.update · connections.delete · connections.list · listings.create · listings.get · listings.update · listings.delete · listings.list · listings.setStatus
Connection credentials are stored as a secretRef (KMS pointer) plus non-secret jsonb config — never in plaintext.
membership · 19 tools
Auto-ship clubs (MOM's continuity programs): plans with cycle definitions, plan products with price overrides, enrollments with billing/member customer split, an enrollment status FSM (active / paused / cancelled / completed), shipment history, and due-shipment batch generation that creates quote orders.
plans.create · plans.get · plans.list · plans.update · plans.delete · plan_products.create · plan_products.get · plan_products.list · plan_products.update · plan_products.delete · enrollments.create · enrollments.get · enrollments.list · enrollments.update · enrollments.delete · enrollments.setStatus · shipment_history.record · shipment_history.list · shipments.generate
subscriptions · 6 tools
Magazine/periodical-style subscriptions: issues remaining/sent, next mail date, hold flag, and renewal processing that issues renewal quote orders.
create · get · list · update · delete · renew
identity · 9 tools
Users, tenant memberships, roles, and permissions. Lives outside tenant RLS by design (it manages the platform-side tables), so it runs on its own restricted pool. User creation is platform-admin only; roles and invitations are tenant-admin operations.
createUser (email, fullName) · listUsers · inviteUser (userId, role: owner | admin | member, default member) · createRole (name, description?) · listRoles · setRolePermissions (roleId, permissionKeys[]) · assignRole (membershipId, roleId) · revokeRole · getEffectivePermissions (userId)
audit · 2 tools
A maker/checker audit trail (generalized from legacy USERACTIVITY): filterable, cursor-paginated log of create/update/delete actions, plus explicit review/authorization of entries.
list (entityType?, entityId?, action?: create | update | delete, actorUserId?, limit default 25, cursor?) · review (entryId)
import_export · 23 tools
Configurable import/export jobs — the modern replacement for MOM's Order Import/Export Wizard: job definitions, source-file structures, field mappings with transform rules (uppercase, lowercase, trim, regex, lookup, concat, dateFormat, custom), run history, and dry-run execution.
jobs.create · jobs.get · jobs.list · jobs.update · jobs.delete · jobs.execute (dryRun?) · source_files.create · source_files.get · source_files.list · source_files.update · source_files.delete · source_files.setContent · field_mappings.create · field_mappings.get · field_mappings.list · field_mappings.update · field_mappings.delete · history.create · history.list · executions.get · executions.list · executions.process · executions.errors
Job types: order, customer, stock, order_export, rates, zones. File types: csv, xml, xlsx, fixed-width, json.
migration · 4 tools
Operator review of durable migration rejection classes and their cutover-gate acceptances.
listRejections · listRejectionAcceptances · acceptRejectionClass · revokeRejectionAcceptance
purge · 5 tools
Permission-gated retention policy, preview, execution, and run evidence for eligible tenant records.
setPolicy · preview · execute · getRun · listRunItems
telemarketing · 12 tools
Call scripts, customer call lists, scheduled/follow-up calls, cancellation, and outcomes recorded into contact history.
createScript · updateScript · listScripts · createCallList · listCallLists · addCallListMembers · removeCallListMember · listCallListMembers · scheduleCall · listScheduledCalls · recordOutcome · cancelScheduledCall
lists · 9 tools
Manual customer lists and criteria-driven segments with evaluation and convergent membership synchronization.
create · update · list · get · evaluate · addMembers · removeMember · listMembers · syncMembership
metrics · 3 tools
Manager-level reporting over optional date ranges: profitability (revenue / COGS / gross margin), salesperson performance (orders, revenue, AOV), and top-N valuable customers.
profitability (from?, to?) · salespersonPerformance (from?, to?) · valuableCustomers (from?, to?, limit default 10)
system · 5 tools
Operational introspection: health (server + database connectivity exercised over the app-role RLS path), the caller identity of the current call, planner maintenance, table sizing, and per-tenant feature flags.
health () · whoami () · reindex () — ANALYZE all tenant tables · files () — row estimates and sizes per table · setting (key, value?) — read/write a tenant flag
Usage metering (orders processed, storage, active users, migration rows) is an internal
seam — a UsageRecorder injected into metered handlers,
consumed today by the managed cloud edition. It is not exposed as tools; there is no
billing surface in the OSS core.
Transports
stdio
pnpm dev:api runs
packages/api/src/index.ts, which connects the MCP
server to StdioServerTransport — the standard
integration for desktop MCP clients and scripts that spawn the server as a child process.
WebSocket
pnpm dev:ws runs
ws-server.ts: a WebSocket server on
ws://localhost:3001/mcp (WS_PORT
to change, 1 MB max payload). Each connection gets its own MCP server instance — cheap
schema registration, no shared mutable state, connections never evict each other.
Authentication headers are read from the WebSocket upgrade request. In production,
browser origins are verified against OPENMOM_ALLOWED_ORIGINS
(non-browser clients, which authenticate with headers instead of an Origin, pass through).
The web app
The React app is itself an MCP client: in dev, Vite proxies
/mcp to
ws://localhost:3001, so the UI drives the exact
same tools an external agent would — no privileged back door.
Schemas in packages/api/src/*/schemas.ts are the
runtime contract — the same Zod definitions validate every call and document every field.
The implementation remains authoritative. Public issue reporting opens with the
repository in January 2027.