§ 00 · Data APIRelease 10 Sept 2026 · v1

The whole catalogue, one record at a time.

What it is

A metered HTTP API over the same database we sell as files. You pay per record returned, at the level of detail you ask for. No subscription and no seats: top up a balance, fetch what your application needs, cache it as long as you like.

Ledger summaryAPI · v1
Unit price
$0.0025
per unit · list 1 · basic 2 · full 4
Records in release139,501 fragrances
Brands · perfumers · notes8,272 · 3,116 · 2,596
Languages in full records23
Minimum top-up$100 = 40,000 units
Current releasev5.15 · 10 Sept 2026
§ 00bWhy the API · three promiseshosted by us · permanent · complete
α

Data and images live on our infrastructure

Every record and every image you receive is served from our own storage and CDN, not linked from a third-party site. Nothing in an answer depends on another website staying online.

β

Nothing ever disappears

Ids are ours and permanent. A fragrance withdrawn at its source stays in the API with its last known content and a status flag; we never delete or re-use an id, so your cache and your links keep working.

γ

The whole record, three times a month

Pyramids, votes, translations, related items and photos come together in one call, refreshed with every release — about three a month; the free index tells you exactly which records changed.

§ 01How it works · three stepsserver-to-server · JSON
1

Top up, get a key

Sign up → Dashboard → Data API. A free test key is there from the start; for real data top up from $100 in BTC, ETH, TRX, XMR or USDT and create a key. Units land on the balance when the payment confirms — minutes for most coins. Up to 5 paid keys per account; each is shown once.

shell
# every call carries your key
curl -H "Authorization: Bearer fk_…" \
  https://fragdb.net/api/v1/account
2

Download the index

Gzipped JSONL, one line per record, each with its kind: every fragrance (id, name, brand, year) and the id of every brand, perfumer and note, with the change status against the previous release. The lists of related fragrances are refreshed with every release and do not count as a change. Free, 5 downloads a day; an unchanged index answers 304 and costs nothing. Search on your side, then ask us only for what moved.

shell
curl -H "Authorization: Bearer fk_…" \
  -H 'If-None-Match: "…"' \
  https://fragdb.net/api/v1/index
# 304 Not Modified — free
3

Fetch records

One id, or a batch of up to 100. The answer keeps your order and your length: unknown ids come back as null in place, listed under problems, and cost nothing. A batch you cannot pay for in full is refused whole with 402. An id repeated inside one batch is returned and charged each time — de-duplicate before you send.

shell
curl -X POST -H "Authorization: Bearer fk_…" \
  https://fragdb.net/api/v1/fragrances/batch \
  -d '{"ids":["…","…"],"level":"full"}'
# X-Balance-Units · X-Daily-Remaining
§ 01bTry it · the responsesample · level full

Every account gets one free test key. It costs nothing, charges nothing and serves the 5 sample records below at every level — enough to write your parser against the real shape before you pay for anything.

shell
curl -H "Authorization: Bearer <your test key>" \
  "https://fragdb.net/api/v1/fragrances/f_9kwkhn9yqx?level=full"
Response headerWhat it tells you
X-Data-Releasethe release this record comes from
X-Balance-Unitsunits left after the call — paid keys only
X-Daily-Remainingrecords left in today’s cap
X-Key-Kindtest — present only on a test key, which is never charged
X-Request-Idquote it if you write to us about one call
Retry-Afterseconds to wait after a 429 (daily cap: until 00:00 UTC) — nothing was charged
ETag / If-None-Matchon the index and on single records: a 304 (or a HEAD) costs nothing and is not counted
Sign up for a free test key Already registered? Dashboard → Data API
Response · f_9kwkhn9yqx · level full
{
  "id": "f_9kwkhn9yqx",
  "name": "Club de Nuit Intense Man",
  "year": 2015,
  "brand": {
    "id": "fb_vsz4efb3je",
    "name": "Armaf"
  },
  "notes": {
    "top": [
      {
        "id": "fn_x2evj9v47c",
        "name": "Lemon",
        "images": {
          "icon": "https://img.fragdb.net/n/2c9fb818077db6a1.webp"
        },
        "weight": 5,
        "opacity": 1,
        "name_i18n": {
          "ar": "الليمون",
          "cs": "Citrón",
          "de": "Zitrone",
          "…": "20 more languages"
        }
      },
      {
        "id": "fn_3qcvzywpkn",
        "name": "Pineapple",
        "images": {
          "icon": "https://img.fragdb.net/n/565cf16d623edda7.webp"
        },
        "weight": 3.65,
        "opacity": 0.95,
        "name_i18n": {
          "ar": "الأناناس",
          "cs": "Ananas",
          "de": "Ananas",
          "…": "20 more languages"
        }
      },
      "… 3 more"
    ],
    "base": [
      {
        "id": "fn_4g85khaq94",
        "name": "Musk",
        "images": {
          "icon": "https://img.fragdb.net/n/0225cc91ba01764a.webp"
        },
        "weight": 3.2,
        "opacity": 0.88,
        "name_i18n": {
          "ar": "المسك",
          "cs": "Pižmo",
          "de": "Moschus",
          "…": "20 more languages"
        }
      },
      {
        "id": "fn_kh4k462kwh",
        "name": "Ambergris",
        "images": {
          "icon": "https://img.fragdb.net/n/fe118dc33561c12f.webp"
        },
        "weight": 3,
        "opacity": 0.85,
        "name_i18n": {
          "ar": "الآمبرغريس",
          "cs": "Ambra",
          "de": "Ambergris",
          "…": "20 more languages"
        }
      },
      "… 2 more"
    ],
    "notes": null,
    "layout": [
      "top",
      "middle",
      "… 1 more"
    ],
    "middle": [
      {
        "id": "fn_gxeqvhejjf",
        "name": "Birch",
        "images": {
          "icon": "https://img.fragdb.net/n/60593bce37738961.webp"
        },
        "weight": 4.08,
        "opacity": 1,
        "name_i18n": {
          "ar": "أخشاب البتولا",
          "cs": "Bříza",
          "de": "Birke",
          "…": "20 more languages"
        }
      },
      {
        "id": "fn_aeed6f0fwy",
        "name": "Jasmine",
        "images": {
          "icon": "https://img.fragdb.net/n/c75c090b6e07693c.webp"
        },
        "weight": 2.6,
        "opacity": 0.76,
        "name_i18n": {
          "ar": "الياسمين",
          "cs": "Jasmín",
          "de": "Jasmin",
          "…": "20 more languages"
        }
      },
      "… 1 more"
    ]
  },
  "votes": 28991,
  "gender": "male",
  "images": {
    "photo": "https://img.fragdb.net/b/af72860f6afae7f1.webp",
    "cutout": "https://img.fragdb.net/b/ff213593e65979db.webp",
    "thumbnail": "https://img.fragdb.net/t/f2130761fd1e063d.webp"
  },
  "rating": 4.07,
  "season": [
    {
      "key": "season_winter",
      "pct": 58.44,
      "votes": 9400,
      "label_i18n": {
        "ar": "الشتاء",
        "cs": "zima",
        "de": "Winter",
        "…": "20 more languages"
      }
    },
    {
      "key": "season_spring",
      "pct": 100,
      "votes": 16200,
      "label_i18n": {
        "ar": "الربيع",
        "cs": "jaro",
        "de": "Frühling",
        "…": "20 more languages"
      }
    },
    "… 2 more"
  ],
  "accords": [
    {
      "id": "fa_b7ecvxh7fp",
      "name": "citrus",
      "strength": 100,
      "name_i18n": {
        "ar": "الحمضيات",
        "cs": "citrus",
        "de": "zitrisch",
        "…": "20 more languages"
      }
    },
    {
      "id": "fa_6av56j7vp4",
      "name": "fruity",
      "strength": 71,
      "name_i18n": {
        "ar": "فاكهي",
        "cs": "ovocný",
        "de": "fruchtig",
        "…": "20 more languages"
      }
    },
    "… 7 more"
  ],
  "related": {
    "also_like": [
      "f_jncs8jkvbp",
      "f_w31jepfj76",
      "… 18 more"
    ],
    "reminds_of": [
      {
        "id": "f_y7bhdp1wbc",
        "no": 936,
        "yes": 6100
      },
      {
        "id": "f_chtz8h9nv9",
        "no": 531,
        "yes": 2500
      },
      "… 18 more"
    ],
    "by_designer": [
      "f_6p4nh7c8gh",
      "f_bjwmne0vps",
      "… 18 more"
    ],
    "in_collection": [
      "f_dhb98akc4b",
      "f_zcv8xxfkkk",
      "… 25 more"
    ]
  },
  "sillage": [
    {
      "key": "sillage_intimate",
      "pct": 4,
      "votes": 987,
      "label_i18n": {
        "ar": "ناعم",
        "cs": "intimní",
        "de": "sanft",
        "…": "20 more languages"
      }
    },
    {
      "key": "sillage_moderate",
      "pct": 32,
      "votes": 7300,
      "label_i18n": {
        "ar": "متوسط",
        "cs": "mírná",
        "de": "moderat",
        "…": "20 more languages"
      }
    },
    "… 2 more"
  ],
  "longevity": [
    {
      "key": "longevity_very_weak",
      "pct": 2,
      "votes": 351,
      "label_i18n": {
        "ar": "ضعيف جداً",
        "cs": "velmi slabá",
        "de": "enttäuschende Haltbarkeit",
        "…": "20 more languages"
      }
    },
    {
      "key": "longevity_weak",
      "pct": 3,
      "votes": 755,
      "label_i18n": {
        "ar": "ضعيف",
        "cs": "slabá",
        "de": "schwach",
        "…": "20 more languages"
      }
    },
    "… 3 more"
  ],
  "perfumers": [],
  "pros_cons": {
    "cons": [
      {
        "text": "Harsh and synthetic start in the opening",
        "likes": 2800,
        "dislikes": 373
      },
      {
        "text": "Some people dislike the harshness or synthetic nature of the fragrance",
        "likes": 2000,
        "dislikes": 304
      },
      "… 6 more"
    ],
    "pros": [
      {
        "text": "Affordable price",
        "likes": 3100,
        "dislikes": 59
      },
      {
        "text": "Good performance and projection",
        "likes": 2500,
        "dislikes": 117
      },
      "… 6 more"
    ]
  },
  "collection": "Club de Nuit",
  "gender_raw": "gender_for_men",
  "description": "Club de Nuit Intense Man by Armaf is a Woody Spicy fragrance for men. Club de Nuit Intense…",
  "price_value": [
    {
      "key": "price_way_overpriced",
      "pct": 2,
      "votes": 305,
      "label_i18n": {
        "ar": "مبالغ في سعره جداً",
        "cs": "velmi předražené",
        "de": "sehr überteuert",
        "…": "20 more languages"
      }
    },
    {
      "key": "price_overpriced",
      "pct": 2,
      "votes": 359,
      "label_i18n": {
        "ar": "مبالغ في سعره",
        "cs": "předražené",
        "de": "etwas überteuert",
        "…": "20 more languages"
      }
    },
    "… 3 more"
  ],
  "time_of_day": [
    {
      "key": "season_day",
      "pct": 99,
      "votes": 16000,
      "label_i18n": {
        "ar": "نهاري",
        "cs": "den",
        "de": "Tag",
        "…": "20 more languages"
      }
    },
    {
      "key": "season_night",
      "pct": 86.99,
      "votes": 14100,
      "label_i18n": {
        "ar": "ليلي",
        "cs": "noc",
        "de": "Abend",
        "…": "20 more languages"
      }
    }
  ],
  "appreciation": [
    {
      "key": "like_love",
      "pct": 45.69,
      "votes": 13200,
      "label_i18n": {
        "ar": "أعشق",
        "cs": "miluji",
        "de": "liebe ich",
        "…": "20 more languages"
      }
    },
    {
      "key": "like_like",
      "pct": 31.8,
      "votes": 9200,
      "label_i18n": {
        "ar": "احب",
        "cs": "mám rád/a",
        "de": "mag ich",
        "…": "20 more languages"
      }
    },
    "… 3 more"
  ],
  "gender_votes": [
    {
      "key": "gvotes_female",
      "pct": 1,
      "votes": 116,
      "label_i18n": {
        "ar": "للنساء",
        "cs": "ženský",
        "de": "weiblich",
        "…": "20 more languages"
      }
    },
    {
      "key": "gvotes_more_female",
      "pct": 0,
      "votes": 27,
      "label_i18n": {
        "ar": "يميل للعطور النسائية",
        "cs": "více ženský",
        "de": "weiblich unisex",
        "…": "20 more languages"
      }
    },
    "… 3 more"
  ],
  "rating_scale": 5,
  "reviews_count": 4400,
  "gender_i18n": {
    "ar": "للرجال",
    "cs": "pro muže",
    "de": "für Männer",
    "…": "20 more languages"
  },
  "source_status": "present",
  "last_seen": "2026-09-10",
  "merged_into": null,
  "change_status": "new",
  "updated_in": "2026-09-10"
}
§ 02Pricing · one unit is $0.0025same price for every record
level · list1 unit
Enough to render a list
1
unit
$0.0025 / record

Identity and the numbers a list needs: id, brand, name, year, gender, rating with vote count, and a thumbnail.

  • id · brand {id, name} · name · year
  • gender · gender_raw
  • rating · rating_scale · votes
  • images.thumbnail
  • accords, notes, perfumers
level · basic2 units
A product card
2
units
$0.005 / record

Everything in list plus the photo, the collection, review count, main accords with their strength and the credited perfumers.

  • all of list
  • images.photo
  • accords [{id, name, strength}]
  • perfumers [{id, name}]
  • collection · reviews_count
level · full4 units
The complete record
4
units
$0.01 / record

The note pyramid as published, seven vote blocks, description, pros and cons, related fragrances, and every label translated inline.

  • all of basic
  • notes {layout, top, middle, base} + name_i18n
  • appreciation · longevity · sillage · season · time_of_day · gender_votes · price_value
  • description · pros_cons
  • related {by_designer, in_collection, also_like, reminds_of}
  • name_i18n · label_i18n · gender_i18n — every label translated
Balance rules

Top-ups are multiples of $50, from $100. Paid units do not expire while the account is open.

Minimum spend is $100 (40,000 units) per 180 days — $16.67 a month — counted from the first top-up. Whatever is left of that minimum is written off at the end of the period; spend more and nothing is. Granted units are never taken for it.

Bought a database file? You get 500 units for 30 days to try the API against the same release.

Paying. BTC, ETH, TRX, XMR or USDT; the invoice holds its rate for the time it shows and units appear when the payment confirms.

Re-requests are charged again. Cache what you fetch — the index tells you which records changed, so you only refetch those.

You pay for what a record holds. If a record has nothing beyond its basic level — the source published no notes, votes or related items for it — a full request costs the basic 2 units, not 4. The X-Charged-Units header on every response says what was taken. When the source fills such a record in, it appears in the index as changed and costs the full price from then on.

Calculator
Level
Units per month40,000
Usage per month$100.00
Per 180 days$600.00
Estimated monthly cost
$100.00

Minimum spend $100 per 180 days is covered.

The whole catalogue once at full level: 139,501 × 4 units = $1,395; at list level $349.

§ 02bReference records · errorsbrands · perfumers · notes

Inside a fragrance record a brand, a perfumer or a note arrives as {id, name} — enough to display, and stable enough to key your own tables on. Ask for the id itself when you want the rest of it.

Resourcebasicfull
GET /v1/brands/{id}name, country, year founded, logo, countsthe same with the description translated
GET /v1/perfumers/{id}name, country, role, counts, photothe same with status and biography translated
GET /v1/notes/{id}name, group, icon, countsthe same with the name and description translated

Priced like fragrances: basic 2 units, full 4. A full request on a reference that has nothing localised is charged as basic — you asked for more and got what exists. Batches of up to 100 work the same way.

When something goes wrong
json
{ "error": { "code": "payment_required",
             "message": "Not enough units for this batch.",
             "required_units": 400,
             "available_units": 120 } }
400bad_requestmalformed body, unknown level, more than 100 ids
401unauthorizedno key, unknown key, revoked key, closed account — one answer for all
402payment_requirednot enough units — required_units · available_units; a test key outside its samples — reason "sample_ids_only"; the index on a test key — reason "paid_keys_only"
403wrong_sitea key for the other storefront’s dataset
404not_foundno record with this id was ever issued — costs nothing
413payload_too_largethe request body is over 256 KB
429rate_limited · daily_cap · index_capover 10/s, 300/min, 20/s per account or the daily cap — Retry-After says when, nothing is charged
451unavailable_for_legal_reasonsthe record is withheld; its id stays reserved
503api_disabledthe API is switched off — balances untouched

Every error has this one shape. Nothing is charged for a refusal — not for 400, not for 402, not for 429.

§ 03Limits · fair useper key · per account · per day
10 / s
requests per key · 300 per minute
100
ids per batch request
50,000
charged records per account per UTC day
5
index downloads per day · 5 keys per account

Requests above a limit are refused with 429 and a Retry-After header, and nothing is charged. A batch that would exceed your balance is refused whole with 402: you are never charged for a partial answer.

Images are served from our CDN for use inside your application. Hot-linking from pages that do not use our data, mirroring the image store, or re-serving images to third parties is outside fair use.

Call the API from your server, never from a browser: keys must not be embedded in client-side code, and cross-origin requests are not answered.

Records never disappear. An item withdrawn at the source stays in the API with its last known content, marked absent; ids are permanent and never re-used.

§ 04What changes between releasesnumbers from the current release
Status in the indexMeaningShare of records
newThe record appears for the first time in this release.100 %

This is the first release on the API, so every record is new; from the next one the table shows the real split. Shares are from the release on the API right now. Releases come about three times a month: one full crawl, and deltas in between that add new records and update existing ones.

Not in the API

User reviews, comments and news texts — those stay in the downloadable files. User-uploaded photos and avatars. Source page URLs and source identifiers: every id and every image URL you see is ours.

Text fields are served as plain text; the note pyramid, vote blocks and relations are structured JSON with stable keys, documented in the OpenAPI spec.

Versioning

Every response carries X-Data-Release. Fields are only ever added within v1; a breaking change ships as v2 with the previous version kept for at least 180 days after notice.

§ 05Questionsmore in the FAQ
Do I need a subscription?+

No. You prepay units and spend them per record. The only recurring rule is the minimum spend — $100 per 180 days, $16.67 a month — which is written off from the paid balance if unused.

Can I search by name?+

Search runs on your side against the free index: id, name, brand, year and change status. Fetch whole records only for the hits you need.

What if a fragrance is removed at the source?+

It stays in the API with its last content and source_status "absent". We never delete an id and never re-use one.

Is there a sandbox?+

/account, /release and the index cost nothing, and an id that was never issued returns null without a charge. Buyers of a database file get 500 trial units.

Get an API key Sign in or sign up · Dashboard → Data APIAPI terms — Terms of Service § 16 · [email protected]