markaDocs

API reference

The ten operations of Marka's public v1 HTTP API, generated from the OpenAPI contract.

Base URL: https://joinmarka.com/api/v1

Every page in this section is generated from apps/docs/openapi/openapi.json, which is itself generated from the route contract in @marka/shared. Nothing here is hand-maintained, so the reference cannot drift from what the handlers implement.

The surface

MethodEndpointOperation
GET/v1/categoriesList active listing categories
GET/v1/listingsList your listings
POST/v1/listingsCreate a draft listing
GET/v1/listings/{id}Get a listing by id
PATCH/v1/listings/{id}Update listing fields
POST/v1/listings/{id}/publishPublish a draft listing
GET/v1/meGet the authenticated account and its plan
GET/v1/ordersList orders on your listings
GET/v1/orders/{id}Get an order by id
GET/v1/searchSearch the 200 most recently listed active listings

Conventions

Money is integer minor units

Every amount — price, shippingFlatAmount, autoAcceptOfferAmount, the price breakdown on an order — is an integer in the minor unit of its accompanying currency. 4500 with "currency": "CAD" is CA$45.00. The API converts nothing, and neither does the SDK.

Writes are gated, reads are not

createListing, updateListing and publishListing require the api_write entitlement when called with an API key, and answer 402 with code: "entitlement_required" without it. Reads are available to any valid key. See Plans & limits.

Lifecycle is not a field

PATCH /v1/listings/{id} updates fields. It cannot change a listing's status: the body is strict, so {"status": "active"} is a 400 that points you at the publish endpoint rather than a 200 that quietly did nothing. Publishing runs the domain's activation guards — a listing needs at least one fulfilment option (pickup or shipping) and at least one order rail (in-person handoff or card checkout), and a shipping-enabled listing needs a shippingFlatAmount above zero.

Search has a horizon

GET /v1/search ranks the 200 most recently listed active listings. That ceiling bounds the candidate set, not the page size — an offset at or past it returns an empty page rather than reaching older items, and no query reaches an item outside it. The same read backs search on the Marka website, so this is not an API-only restriction.

A city that matches nothing in the catalogue returns no results, rather than dropping the location filter and answering with the whole country.

Orders are read-only, and contain personal data

There is no write path for orders on this API. Order fulfilment happens in the Marka app.

checkoutShippingDetails is PII

On the card-checkout rail, an order's checkoutShippingDetails carries the name, email, phone and postal address the buyer supplied at checkout. It is exposed deliberately — a seller cannot buy a shipping label without it — but it is personal data. Handle it accordingly, and do not log it. It is null on the in-person pickup rail, where no such details are collected.

The buyer is otherwise identified only by an opaque buyerId; there are no top-level buyer name or email fields.

Pagination

List endpoints take limit and offset, and return the records alongside the limit and offset that were applied plus a hasMore boolean. Ordering is newest-first for listings and orders, and relevance-ranked for search.

A limit outside the allowed range is a 400, not a silent clamp: a published contract that quietly returns a different page size than the one asked for is a contract that lies to a generated client.

GET /v1/categories is the exception — it has no pages at all. Categories are the distinct categoryPath values across active listings, grouped and counted, ordered by count descending. Its limit truncates the tail of that single list; a lower limit never surfaces different categories.

Errors

One envelope, { error, code? }, for every non-2xx response. See Authentication → Errors for the status and code tables.

On this page