PSXI API

A free, public, read-only API for FFXI private-server market data. One request returns an hourly-refreshed snapshot of every auction house and bazaar item on a server, with sale statistics. No API key required.

Endpoint

A single GET endpoint, one snapshot per server:

GET https://www.psxi.gg/api/v1/market/{serverSlug}

Live servers: horizonxi. Unknown or not-yet-live servers return 404. The response is CORS-enabled (Access-Control-Allow-Origin: *) so you can call it from the browser.

Quick start

curl https://www.psxi.gg/api/v1/market/horizonxi

Response shape

Top-level meta plus a data array, one entry per item (sorted by itemId). Any field is null when there is no data: ah is null for items never seen on the AH, bazaar is null for items with no bazaar history.

{
  "meta": {
    "server": "horizonxi",
    "generatedAt": "2026-06-25T22:00:00.000Z",
    "statsWindowDays": 7,
    "itemCount": 4123,
    "disclaimer": "Bazaar figures are estimates..."
  },
  "data": [
    {
      "itemId": 640,
      "itemName": "Mythril Sheet",
      "categorySlug": "smithing",
      "ah": {
        "currentStock": 12,
        "currentStackStock": 3,
        "single": { "lastSale": 8000, "lastSaleDate": "2026-06-25T19:14:00.000Z",
                    "avg": 8200, "median": 8000, "volume": 41, "min": 7000, "max": 9500 },
        "stack":  { "lastSale": 90000, "lastSaleDate": "2026-06-24T08:02:00.000Z",
                    "avg": 91000, "median": 90000, "volume": 6, "min": 85000, "max": 99000 }
      },
      "bazaar": {
        "median": 8500, "avg": 8600, "minPrice": 8000, "maxPrice": 9900,
        "listingCount": 5, "lastSuspectedSale": "2026-06-25T11:30:00.000Z", "estSaleVolume7d": 3
      }
    }
  ]
}

Field reference

AH statistics (avg, median, volume) cover a rolling 7-day window. lastSale is the most recent sale of all time, so even thin items return a price. Prices are in gil.

FieldTypeDescription
itemIdnumberFFXI item ID.
itemNamestringHuman-readable item name.
categorySlugstring|nullAH category slug (e.g. smithing).
ah.currentStocknumber|nullSingle items currently listed on the AH.
ah.currentStackStocknumber|nullStacks currently listed on the AH.
ah.single / ah.stackobjectSale stats split by single-item vs full-stack listings.
ah.*.lastSalenumber|nullMost recent sale price (all-time).
ah.*.lastSaleDatestring|nullISO 8601 timestamp of the last sale.
ah.*.avgnumber|nullMean sale price over the last 7 days.
ah.*.mediannumber|nullMedian sale price over the last 7 days.
ah.*.volumenumberNumber of sales in the last 7 days (0 if none).
ah.*.min / ah.*.maxnumber|nullMin/max sale price over the last 7 days.
bazaar.median / avgnumber|nullAcross current ONLINE listings (asking prices, not sales).
bazaar.minPrice / maxPricenumber|nullCheapest / priciest current online listing.
bazaar.listingCountnumberCurrent online listings (one per seller).
bazaar.lastSuspectedSalestring|nullWhen a listing last disappeared (estimate, see below).
bazaar.estSaleVolume7dnumberListings that vanished in the last 7 days (estimate).
Bazaar numbers are estimates. Bazaars have no sale receipts, so avg/median reflect current asking prices, and lastSuspectedSale/estSaleVolume7d are inferred from listings that disappeared, which may have sold or simply been delisted. Treat them as directional, not authoritative. AH numbers come from real sale records.

Caching & freshness

Data is recomputed at most once per hour and served from the CDN with Cache-Control: public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400. Polling more often than hourly just returns the same cached payload, so please don't. Use the meta.generatedAt timestamp to tell when the snapshot was built.

Rate limits & fair use

The endpoint is rate-limited to 2 requests per minute per IP at the edge. Because the data only changes hourly, one fetch per hour per server is all you need. Clients that exceed the limit are blocked (HTTP 403) until the window resets.

This API exists so you don't have to scrape the site. Hammering the live pages instead of using this endpoint may get your IP blocked. If you need higher volume, a different cadence, or data we don't expose here, get in touch and we'll work something out.