Skip to content
xivdyetools.app ↗

Dyes ​

7 endpoints · 125 dyes · Schema v2 · stainID-keyed

The full dye database — 125 standard dyes, keyed by stainID. Facewear colors are no longer served as dyes; legacy negative IDs return an explanatory 404.

Every dye in a response is the same Dye Object — every card on this page carries a Fields fold listing its 19 fields (/categories and /consolidation-groups return summaries, not dyes). Two of them are easy to confuse:

  • stainID is the canonical key (the game's stain table, 1–254); itemID is the legacy per-dye item.
  • marketItemID is for market-board lookups only and is never a dye lookup key. Since Patch 7.5, 105 dyes share three consolidated items (52254 / 52255 / 52256), so look prices up on Universalis by marketItemID — never by a dye's legacy itemID — and use /v1/dyes/consolidation-groups to learn which dyes share which item.

GET /v1/dyes ​

List all dyes with filtering, sorting, and pagination. Returns 125 entries across ~3 pages at the default perPage of 50.

GET/v1/dyesList all dyes with filtering, sorting, and pagination.…

List all dyes with filtering, sorting, and pagination.

Parameters · query
Exact category name, case-sensitive
name · brightness · saturation · hue · cost
asc or desc
Page number (1–1000)
Items per page (1–200; the API default is 50)
en · ja · de · fr · ko · zh
Only (true) or never (false) metallic dyes
Only / never pastel dyes
Only / never dark dyes
Only / never Cosmic Exploration dyes
Only / never Ishgardian dyes
Only / never dyes acquired from vendors
Only / never dyes acquired by crafting
Only / never premium-cost dyes (curated list)
Patch 7.5 group
Lower bound on vendor cost (integer ≥ 0)
Upper bound on vendor cost (integer ≥ 0)
Comma-separated IDs to drop (max 50; itemID or stainID, auto-detected)
GET /v1/dyes?order=asc&page=1&perPage=10&locale=en
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask

GET /v1/dyes/:id ​

Look up a single dye. The ID type is inferred by numeric range — see ID auto-detection. A consolidated market item (52254–52256) is rejected with a hint pointing at /v1/dyes/consolidation-groups; a legacy negative Facewear ID answers 404 with the color's new slug, name and hex.

GET/v1/dyes/:idLook up a single dye; ID type inferred by range.…

Look up a single dye; ID type inferred by range.

Parameters · path
itemID (≥ 5729) or stainID (1–254), auto-detected
Parameters · query
en · ja · de · fr · ko · zh
GET /v1/dyes/5729?locale=en
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask

GET /v1/dyes/stain/:stainId ​

Explicit stainID lookup — bypasses range-based auto-detection. Use this when you specifically have a stainID and want to be unambiguous.

GET/v1/dyes/stain/:stainIdLook up a dye by stain table ID (1–254).…

Look up a dye by stain table ID (1–254).

Parameters · path
stainID (positive integer, 1–254; 404 if unassigned)
Parameters · query
en · ja · de · fr · ko · zh
GET /v1/dyes/stain/1?locale=en
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask

Search dyes by name. Case-insensitive substring match; with a non-English locale the localized names are searched and returned. Returns an array (not paginated) of every matching dye.

From core 5.4.0, the localized search (any non-English locale) is also accent-, ß- and width-insensitive (q=schneeweiss&locale=de matches Schneeweißer), so q= may return more rows than before. The default English search is unchanged.

GET/v1/dyes/searchCase-insensitive substring match on names; localized when locale is set.…

Case-insensitive substring match on names; localized when locale is set.

Parameters · query
Substring to match against dye names (max 100 characters)
Search against localized names and return localizedName
GET /v1/dyes/search?q=snow&locale=en
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask

GET /v1/dyes/categories ​

List all dye categories with their dye counts.

GET/v1/dyes/categoriesAll dye categories with their counts.…

All dye categories with their counts.

cURL$ curl https://data.xivdyetools.app/v1/dyes/categoriesJavaScriptconst r = await fetch('https://data.xivdyetools.app/v1/dyes/categories');
const { data } = await r.json();
GET /v1/dyes/categories
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask

GET /v1/dyes/batch ​

Look up multiple dyes by ID in a single request. Returns the dyes found and a notFound array for any IDs that didn't resolve.

GET/v1/dyes/batchMultiple dyes by ID in one request; notFound array for misses.…

Multiple dyes by ID in one request; notFound array for misses.

Parameters · query
Comma-separated IDs (max 50)
How to read each ID: auto-detect by range, or force item / stain
en · ja · de · fr · ko · zh
GET /v1/dyes/batch?ids=5729%2C5730%2C5731&idType=auto&locale=en
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask
json
{
  "success": true,
  "data": {
    "dyes": [ { "itemID": 5729, "name": "Snow White", ... }, ... ],
    "notFound": []
  },
  "meta": { ... }
}

GET /v1/dyes/consolidation-groups ​

Patch 7.5 consolidation metadata. In Patch 7.5, 105 individual dyes were reorganized into three consolidated dye items (Type-A, Type-B, Type-C). This endpoint exposes which dyes belong to which group and whether consolidation is currently active in the game.

Consolidation is active (since April 2026) — all three consolidated itemIDs (52254, 52255, 52256) are populated, and the marketItemID field on each consolidated dye points to the consolidated item rather than the legacy per-dye itemID. Use this endpoint to discover which legacy itemIDs map to which consolidated parent, e.g. when caching market-board prices.

GET/v1/dyes/consolidation-groupsPatch 7.5 consolidation groups A / B / C and their members.…

Patch 7.5 consolidation groups A / B / C and their members.

cURL$ curl https://data.xivdyetools.app/v1/dyes/consolidation-groupsJavaScriptconst r = await fetch('https://data.xivdyetools.app/v1/dyes/consolidation-groups');
const { data } = await r.json();
GET /v1/dyes/consolidation-groups
STATUS · TIME · X-REQUEST-ID — after Send
// tap Send — nothing is fetched until you ask
json
{
  "success": true,
  "data": {
    "consolidationActive": true,
    "groups": [
      {
        "type": "A",
        "consolidatedItemID": 52254,
        "dyeCount": 85,
        "dyes": [
          { "itemID": 5729, "stainID": 1, "name": "Snow White" }
        ]
      },
      { "type": "B", "consolidatedItemID": 52255, "dyeCount": 9, "dyes": [] },
      { "type": "C", "consolidatedItemID": 52256, "dyeCount": 11, "dyes": [] }
    ],
    "unconsolidated": {
      "count": 20,
      "dyes": []
    }
  },
  "meta": {}
}

FINAL FANTASY XIV © 2010-2026 SQUARE ENIX CO., LTD. All Rights Reserved.
XIV Dye Tools is a fan-made application and is not affiliated with or endorsed by Square Enix. · Discord ↗