markaDocs
Architecture

Architecture

How Marka is built — the canonical listing model, the mutation pipeline every state change flows through, the two order rails, search, and the AI seam.

These pages describe how Marka works underneath the API — the models and invariants the endpoints are a view onto. You do not need any of it to make a call. You need it when you are deciding how much to trust a response, why an operation is shaped the way it is, or what happens between your request returning and the effect being visible somewhere else.

Everything here is written from the code it describes, and every page names the files that make it true. Where a behaviour is deliberately narrower than it could be, that is stated rather than smoothed over.

Get an API key to try the API on your own account, then make your first call with Getting started.

The shape of the system

Marka is a canonical-listing marketplace. A seller creates one Listing. That listing is the single record of what is for sale; every other representation of it — a buyer-facing search result, a projection onto eBay, the snapshot frozen into an order — is derived from it and knows which one it came from.

Around that sit four things worth understanding separately:

Four invariants that explain most of the design

Money is an integer in the minor unit of its currency, everywhere. Not at the edges — the whole way through. 4500 with "currency": "CAD" is CA$45.00 in the database, in the domain layer, in the order's frozen price breakdown, and in the unit_amount handed to Stripe. Nothing converts on the way, and a fractional amount is rejected at the edge rather than rounded quietly. The only conversion to major units happens at the display edge, when a number becomes a string a human reads.

Every state change is audited, and the audit is written in the same transaction as the change. Not appended afterwards by a listener that might not run. The audit row, the domain events, and the entity write commit together or not at all. See the mutation pipeline.

The seller is the merchant of record. Marka never holds the money. Card payments are Stripe Connect direct charges on the seller's own connected account, and the marketplace application fee is fixed at zero — not discounted, structurally absent. See payments and rails.

Publishing is a human decision. Every programmatic surface — the API, the SDK, both MCP servers, the in-app AI assistant — can create and edit drafts. Publishing a listing is what makes it visible to buyers and commits a seller to selling the thing, and it is deliberately excluded from every AI surface. The HTTP API exposes it as its own endpoint with its own entitlement check, never as a field you can set.

Where this is written down

AreaCode
Pure business logic, no I/Opackages/domain
The only package that touches Postgrespackages/db
Types, money helpers, the event vocabularypackages/shared
Typesense indexing and queryingpackages/search
eBay / Shopify / shipping adapterspackages/connectors-*
Durable background workersapps/iii-engine/workers/*
The Mastra AI serviceapps/ai
Web app, API routes, server actionsapps/web

On this page