Developer beta

Market price API

Build community tools with Last Epoch unique, set, exalted-affix, and idol-combination asking prices.

Quick start

Get overall unique, set, exalted-affix, and idol-combination asking prices as JSON. No account or API key is required.

First fetch active cycles and choose an ID. Use defaultCycleId when present, or let the user choose. Unique and affix feeds return the complete cycle snapshot; idol prices are paginated.

Use https://bazaar.leoverlay.com as the API origin. Prices are integer gold values; timestamps are Unix milliseconds. The examples use Swordfish as a cycle ID.

GET /v1/cycles
GET /v1/pricing/uniques?cycle=Swordfish
GET /v1/pricing/affixes?cycle=Swordfish
GET /v1/pricing/idols?cycle=Swordfish&page=0

Unique and set prices

GET /v1/pricing/uniques?cycle={cycle} returns schemaVersion, cycle, catalogueRevision, and quotes. Each quote contains identity, medianGold, listingCount, status, snapshotAt, and expiresAt. Last-known references also include lastKnownAt.

The identity contains uniqueId, legendaryPotential, and variantAffixIds. ID 0 is valid. Empty variantAffixIds means the overall item price; populated IDs identify an exact native variant. Keep LPs and variants separate. Overall item prices overlap their native variants, so do not add their counts or average their medians. Roll-filtered prices and rules are not included.

Fresh unique and set quotes with 1–9 priced listings expose the observed sample median while retaining status insufficient-data. Treat these as low-volume observations, not qualified price references. Grouped overview and roll detail responses retain the observed minimum and maximum alongside p50Gold; historical series keep their sample requirements.

Load /catalogue/uniques/{catalogueRevision}.json from this website using the revision in the response. Catalogue schema 4 maps uniqueId to names, itemType, subType, and pricing LP/variant options. Names are labels, not keys. Items without pricing LP use LP 0.

Icons use /catalogue/uniques/{catalogueRevision}/icons/{uniqueId}.webp. Some excluded catalogue entries have no icon. Before the first snapshot, catalogueRevision can be null and quotes empty.

Add weaversWill=1 to unique pricing URLs to include Weaver’s Will items and range prices. This also applies to POST quote/history URLs; their JSON bodies are unchanged. Without the parameter, responses retain the pre-WW catalogue view and omit WW items. Direct WW quote/history/roll requests require the parameter.

Exalted affix prices

GET /v1/pricing/affixes?cycle={cycle} returns schemaVersion, cycle, and quotes. Each quote contains identity, medianGold, listingCount, status, snapshotAt, and expiresAt. There are no rule definitions, percentile ranges, or history in this feed.

The identity contains itemType, affixId, and tier. Item type and affix ID are numeric game IDs. Tier uses the stored zero-based value: 5 means T6 and 6 means T7. Keep the same affix separate across item types and tiers. Prices pool equipment bases and forging potential.

The feed does not include affix names; consumers need an affix-ID label mapping. Before the first snapshot, quotes can be empty.

Node.js consumer
node affix-prices.mjs Swordfish

Idol combination prices

GET /v1/pricing/idols returns overall prices for up to 50 exact idol combinations per page. Supply an active cycle ID. page starts at 0. Use page, pageSize, and total to fetch additional pages.

Each quote has a named identity: cycle, itemType, subType, rarity, corrupted, primordial, weaversWill, weaversTouch, and affixes. Affixes carry id, stored tier, type, specialType, and sealedType. Keep every identity field when comparing combinations. Idol tiers are identity values, not an equipment-style T6/T7 filter. id is an opaque cohort ID.

medianGold is the overall median asking price; listingCount is the number of observed priced listings. These are not completed sales or valuations of a particular roll. Use a quote only when status is available and expiresAt is in the future. stale and insufficient-data quotes have null medianGold; missing prices are not zero. Expiry and snapshotAt are per quote, in Unix milliseconds.

Pages are ordered by current availability, then descending overall median and cohort ID. They are not an atomic export: refreshes can move combinations between pages. Deduplicate by id and refresh from page 0 periodically. An empty feed can have a null catalogueRevision before pricing is configured.

Read a page
GET /v1/pricing/idols?cycle=Swordfish&page=0

Idol names and icons

Fetch /catalogue/idols/{catalogueRevision}/catalogue.json from this website using the revision in the idol response. This is the modifier-catalogue revision (64 hex characters), not the unique catalogue revision. The idol manifest identifies the latest version; saved responses must use their own revision. Versioned files and icons are immutable. Retain old revision directories when publishing a new catalogue.

Catalogue schema 1 contains bases with itemType, subType, names, and iconUrl, plus affixes with id, names, and kind. Names are keyed by locale; use en-US as the fallback. Treat names as labels, never identity keys.

Node.js consumer
node idol-prices.mjs Swordfish

import { createIdolPriceReader } from './idol-prices.mjs';
const reader = createIdolPriceReader('Swordfish');
await reader.refresh();
const prices = reader.getIdolPrices(); // Only fresh, available quotes

Price status and freshness

Use medianGold only when status is available and expiresAt is in the future. Missing prices are null, never zero. listingCount describes observed priced listings, not completed sales or total market stock.

Unique prices may have status last-known. These are historical references: show lastKnownAt alongside the price and stop using them at expiresAt. snapshotAt is the aggregate timestamp, not the date of the original reference.

All other statuses mean no usable current quote. An old price is not made current by a successful refresh or a 304 response.

Refresh and errors

Poll about hourly with jitter. Store ETag and send it unchanged in If-None-Match. A 304 reuses the existing body without extending expiresAt. Recheck each quote’s expiry when displaying it.

Price responses cache for at most 60 seconds, capped by expiry. Cycle lists and catalogue manifests cache for up to five minutes. Versioned catalogue assets are immutable.

Treat network errors, invalid JSON, unknown schema versions, and missing catalogue mappings as failed refreshes. Archived cycles are not available; use IDs from the active-cycle endpoint.

HTTP statusAction

304

Reuse the cached body without extending expiry.

400

Correct the request parameters.

409

Re-read active cycles and choose again.

429 / 503

Respect Retry-After before retrying.

Request limits

Unique, affix, and idol price feeds share a limit of 30 requests per IP per minute, including conditional requests and other overview reads. Active cycles allow 120 requests per IP per minute. These beta limits do not guarantee capacity or uptime.

The idol example spaces page requests three seconds apart. Reuse one reader per cycle, avoid overlapping refreshes, and coordinate request pacing across readers sharing an IP.

The documented GET endpoints support credential-free CORS and expose ETag, Retry-After, and Cache-Control.

Unique price Node.js example

Run the example with Node 22 or newer and an active cycle ID. It reads the minimal feed and matching catalogue, retains ETags, and exposes only fresh, available quotes.

Keep one reader per cycle. Call refresh() on your schedule and getUniquePrices() when displaying prices. Expiry is checked on every read; failed refreshes clear usable output. The example excludes last-known references and reports Retry-After without retrying automatically.

node unique-prices.mjs Swordfish

import { createUniquePriceReader } from './unique-prices.mjs';
const reader = createUniquePriceReader('Swordfish');
await reader.refresh();
const prices = reader.getUniquePrices();

Coverage and limitations

These are community-observed asking prices, not sales, total stock, or individual stat-roll valuations. Coverage depends on the searches players make. Sample counts do not establish independent sellers or protect against manipulated listings.

The feed supports external price-aware tools. Importable game-filter generation, automatic in-game updates, and exact unique-ID matching have not been verified. The example outputs data, not a game filter.

Multiple uniques can share a base type. Keep unknown or unsupported items visible; do not turn an unpriced item into a hide rule. Preserve build-specific keep rules. Validate a real exported filter and its import behavior before advertising filter support.

Data reuse

You may use, copy, adapt, and redistribute our aggregate price data for free, including in commercial tools. Credit Last Epoch Overlay and link to https://www.leoverlay.com/developers wherever you display or distribute the data.

This permission covers our aggregate price data. It does not grant rights to game artwork, names, or other third-party assets, and does not imply endorsement by Eleventh Hour Games. Data and API availability are provided without guarantees; respect the published request limits.