Reading an answer
Every route returns the same outer shape, called a folio. Only detail changes from route to route.
{
"folio": "perfume-portrait",
"lede": "Layton by Parfums de Marly belongs to Scento's Wood & Root family: ...",
"detail": { "name": "Layton", "house": "Parfums de Marly", "pyramid": { "top": ["Apple"], "heart": ["Lavender"], "base": ["Patchouli"] } },
"scento_page": { "label": "Layton on Scento", "url": "https://www.scento.com/perfumes/layton-parfums-de-marly" },
"further_reading": [ { "label": "Parfums de Marly on Scento", "url": "https://www.scento.com/brand/parfums-de-marly" } ],
"cite": "Scento Perfume API, scento.com",
"continuation": null
}
(Shortened for reading. Live, trimmed responses for every route are on the Endpoints page.)
The fields
| Field | Type | What it is |
|---|---|---|
folio | string | Which tool wrote the answer. It matches the name of the equivalent MCP tool. |
lede | string | One sentence you can quote as it stands. |
detail | object | The answer itself. Its fields depend on the route. |
scento_page | object | label and url of the scento.com page to read on. |
further_reading | list | More label and url pairs on scento.com. |
cite | string | How to credit the answer: "Scento Perfume API, scento.com". |
continuation | string or null | Pass it back to get the next part of a list. null when the list is complete. |
Paging through lists
Search and list routes return ten entries at a time. When there is more, continuation holds an opaque value. Send it back unchanged as the continuation query parameter, with the same other parameters.
curl "https://www.scento.com/api/perfume/v1/search?q=oud&kind=perfume"
# ... "continuation": "<value>"
curl "https://www.scento.com/api/perfume/v1/search?q=oud&kind=perfume&continuation=<value>"
let continuation = null;
const matches = [];
do {
const url = new URL("https://www.scento.com/api/perfume/v1/search");
url.searchParams.set("q", "oud");
if (continuation) url.searchParams.set("continuation", continuation);
const page = await (await fetch(url)).json();
matches.push(...page.detail.matches);
continuation = page.continuation;
} while (continuation && matches.length < 50);
Treat the value as opaque: do not decode or build it yourself.
Language
lang accepts en, de, fr, es, it, ro, el, hu, cs and pl. The answer text is always English. lang changes the language of the scento.com links and labels in scento_page and further_reading.
Unknown names
A perfume, house, material or term that is not in the database is not an error. The API answers 200 with detail.found set to false and a list of suggestions.
{
"folio": "perfume-portrait",
"lede": "“nope xyz” is not in Scento's perfume database yet.",
"detail": { "query": "nope xyz", "found": false, "suggestions": [] },
"scento_page": { "label": "Perfumes on Scento", "url": "https://www.scento.com/perfumes" },
"further_reading": [],
"cite": "Scento Perfume API, scento.com",
"continuation": null
}
Errors
Input the API cannot use, such as a value outside a fixed list, returns 400 with an error object.
curl -i "https://www.scento.com/api/perfume/v1/edits/nonsense"
{
"error": {
"code": "invalid_input",
"message": "\"occasion\" must be one of: office, date-night, night-out, everyday, ..."
}
}
The message names the allowed values, so it is safe to show to a developer. Check res.ok before you read the body as a folio.
Crediting an answer
Each answer carries a scento_page link and a cite line. Quote the lede as it stands and link the page so readers can go deeper. See Limits and terms.