API Conventions
This section covers the core mechanics of the Marketfront API, including error handling, rate limiting, and caching.
Authentication
All requests require a Bearer token in the Authorization header. See the Authentication guide for key management, environment setup, and security best practices.
Money & amounts
Every monetary value is a self-describing money object: the amounts breakdown carries a currency (ISO 4217, e.g. USD) and each amount is a decimal string — "10.50", never a bare JSON number.
Code
Send amounts the same way you receive them — as strings (e.g. amounts.tip on validateOrder).
Why strings? Parsing money as a JSON number invites IEEE-754 drift (0.1 + 0.2 !== 0.3). A decimal string parsed with a decimal/big-decimal type on your side is exact. Currency is explicit so you never have to assume USD.
Schema inheritance
Some schemas in the API reference render as allOf: [{$ref: Base}, {additional properties}]. Read this as inheritance — the object has all the fields from the referenced base schema, plus the additional ones listed. For example, DeliveryFulfillment extends Fulfillment (adding address, deliveryType, instructions), and OrderPlaceRequest extends OrderValidateRequest (adding payment).
This is why a field can appear once and apply everywhere. The required client object is declared on OrderCore, so both validateOrder and placeOrder carry it — see End-user client context.
Decimal places per currency
An amount must not carry more decimal places than its currency's minor unit, or the request is rejected with 422 PRECISION_EXCEEDED. Round to the currency's scale before sending.
| Minor-unit scale | Example currencies | Example |
|---|---|---|
| 2 (default) | USD, EUR, GBP, CAD, AUD | "10.50" |
| 0 | JPY, KRW, VND, CLP | "1000" |
| 3 | BHD, KWD, OMR, TND | "10.500" |
Error Handling
All error responses use RFC 9457 application/problem+json format. Every error includes machine-readable fields (errorCategory, retryable, retryAfter) for programmatic handling. Domain-specific errors include an errorCode field identifying the specific issue.
The API supports content negotiation via the Accept header — request text/markdown for a compact text representation suitable for AI agents and CLI tooling. See the Error Reference for full details.
HTTP Status Codes
| Status | Meaning |
|---|---|
400 | Invalid request body, missing fields, or domain-specific errors (see errorCode) |
401 | Missing or invalid API key |
404 | Resource does not exist |
409 | Conflict (e.g., order token already used) |
422 | Request-shape or semantic validation of the request body failed (e.g. malformed body, PRECISION_EXCEEDED) |
429 | Rate limit exceeded |
500 | Unexpected server error |
Order/business validation is different
validateOrder never returns a 4xx for business or order problems (item unavailable, store closed, minimum not met, etc.). It returns HTTP 200 with isValid: false and a populated errors[] on the Order body. Only malformed requests and authentication failures produce 4xx from that endpoint. See Validation vs Placement in the Order Lifecycle guide.
Error Codes
Domain-specific errors include an errorCode field.
Cart & Item Errors
| Code | Description | Action |
|---|---|---|
CART_EMPTY | Cart has no items | Add items before validating |
CATALOGSET_REQUIRED | Cart creation requires a catalogSetId | Include catalogSetId when cart is null |
ITEM_UNAVAILABLE | Item no longer available | Remove from cart and re-validate |
MODIFIER_REQUIRED | Required modifier group has no selection | Prompt user to select |
ORDER_BELOW_MINIMUM | Below store's order minimum | Add more items |
Store Errors
| Code | Description | Action |
|---|---|---|
STORE_CLOSED | Store is no longer open | Re-discover stores |
STORE_NOT_FOUND | Store does not exist | Re-discover stores |
CATALOGSET_NOT_FOUND | CatalogSet does not exist | Re-discover for updated catalogSetId |
Payment Errors
| Code | Description | Action |
|---|---|---|
PAYMENT_FAILED | Transient processing failure | Retry with the same idempotency key |
PAYMENT_METHOD_INVALID | Payment method payload not valid | Re-prompt the user for payment details |
PAYMENT_DECLINED | Declined by issuer | Use a different payment method |
Order Errors
| Code | Description | Action |
|---|---|---|
ORDER_TOTAL_DIFFERENT | Total changed since validation | Re-validate the order |
ORDER_ALREADY_PLACED | Idempotency-key conflict | This order was already placed |
Open enum: order errors[].code
The errors[].code values on an order (both validateOrder 200 responses and placeOrder 4xx ProblemDetail responses) are an open enum (x-extensible-enum). The set above lists the current values but is not exhaustive — new codes may be added as new failure modes are identified. Clients must handle unknown values as OTHER and must not hard-fail on an unrecognized code. Do not deserialize into a closed/strict enum type. See the full code table with suggested actions in the Order Lifecycle guide.
This is distinct from the top-level ProblemDetail.errorCode field (a single string naming the overall failure reason on a 4xx place response).
Address Errors
| Code | Description | Action |
|---|---|---|
ADDRESS_INVALID | Could not be validated | Verify the address |
ADDRESS_OUT_OF_RANGE | Outside store's delivery zone | Choose a different store |
Authentication Errors
| Code | HTTP | Description | Action |
|---|---|---|---|
SESSION_USER_REQUIRED | 401 | Endpoint requires an authenticated user identity | Ensure the end user is signed in before making this request |
Retry Strategy
| Category | Retryable? | Strategy |
|---|---|---|
401 Unauthorized | No | Fix your API key |
400 Bad Request | No | Fix the request |
404 Not Found | No | Resource doesn't exist |
429 Too Many Requests | Yes | Wait for X-RateLimit-Reset, then retry |
500 Internal Error | Yes | Exponential backoff (1s, 2s, 4s, max 30s) |
Always include the
requestIdwhen contacting support about a specific error.
Rate Limits
Per-partner rate limits ensure fair usage and platform stability.
| Endpoint Type | Limit | Examples |
|---|---|---|
| Read operations | 1,000/min | /stores/discover, /catalog-sets/{catalogSetId} |
| Write operations | 100/min | /orders/validate, /orders/place |
| Store discovery | 60/min | /stores/discover (also counted under reads) |
Sandbox rate limits are 5x higher than production.
Rate limits are scoped to your partner organization — all keys belonging to the same organization share the same quota.
Every response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
When rate limited, the API returns 429 Too Many Requests. Read the X-RateLimit-Reset header to know when to retry. If the header is missing, use exponential backoff starting at 1 second.
Caching Strategy
| Data Type | Strategy | Why |
|---|---|---|
| Store results | Never cache | Store status changes constantly |
| CatalogSets | Cache aggressively | Immutable — use catalogSetId as cache key |
| Validation tokens | Expire in 15 min | Security and price accuracy |