2.9
The 2.9 line went out in nine small releases in October, from 2.9.0 to 2.9.8. Most of the work sits behind the data: the October audit that aligned our names with Kew's checklist, the first trait import from TRY, and a back office that can keep up with the corrections both produce.
Names, aligned with WCVP
The audit compared every accepted name we hold with the World Checklist of Vascular Plants. Applying its findings needed changes to the API itself.
Nomenclature now has its own source order (2.9.4): human-reviewed corrections first, then WCVP, IPNI and World Flora Online, then GBIF. An author or publication year written before we recorded provenance ranks with GBIF, so Kew's checklist can correct it and a GBIF match alone cannot. The first 27 000 WCVP values of the audit had to go in as community corrections; later batches enter under their own name.
An accepted correction may now rename a species. The genus follows the new name, the rank follows its form, and the old name stays as a synonym. When a proposed name points at a genus we already hold, the queue proposes a re-link instead of a rename.
The name validator accepts the spaced hybrid sign ("× Agropogon lutosus"), hybrid epithets below species rank ("Rosa × odorata var. erubescens"), section aggregates and one-letter epithets. Near-duplicates such as "Aster handelii" beside "Aster × handelii" are refused at creation (2.9.1).
Plants linked to their species
52 601 plants had no link to their root species, so GET /api/v1/plants/:id returned main_species, image_url, year and bibliography as null for them. A root species now claims its plant when created, and the missing links were backfilled (2.9.2).
Nested record endpoints are scoped to their parent (2.9.6). /api/v1/genus/hieracium/species/eruca-vesicaria used to answer with Eruca vesicaria; it now returns a 404, as the nested list already did.
TRY traits, in production
The TRY export ran against production on 9 October: 267 289 trait claims on 76 665 species, each stored as a fact naming the TRY dataset it comes from. Where our column was empty, the value was promoted into it, 84 159 times. Where a stronger source already held a value, the TRY claim stays on file and the two can be compared.
You can see those comparisons without the API. Every species page in Explore has a Data sources tab (2.9.6) listing, field by field, the value we show and what each source claims, with evidence type, number of observations and a link to the source record.
Back office
The corrections review queue was rebuilt (2.9.6): changes shown as a diff against the current record, filters by status and check, bulk accept and reject, and decisions that return to the same filtered page. A correction the ingester refuses now says why instead of reporting success.
Fixes
Password sign-in on trefle.io had been broken since 8 September: a correct password signed you in and the session was discarded in the same request, landing you on the home page with no message. Fixed in 2.9.5.
The Explore home and the genus pages ordered by a score that was null for every species, which is why they showed unillustrated bryophytes first. They order by GBIF occurrences now.
Under the hood, Rails moved from 8.0 to 8.1 with its new defaults (2.9.0 and 2.9.3). Public API responses are byte-identical.
2.9.7: ranges, page size, synonyms
range[…]reads both bounds as included on every endpoint, accepts decimals and negatives, and lets either side stay open (range[ph_minimum]=5.5,). A bound that is not a number answers400instead of being read as 0. See Filtering.per_page(1 to 100) sets the page size on every collection. See Pagination.- List rows carry
synonyms_countand alinks.synonymslink instead of the full list of names, andGET /api/v1/species/:id/synonymspages through them. A species detail embeds its first 50 synonyms: Rosa canina has more than a thousand, and its record weighed 641 KB. GET /api/v1/distributions?q=Francefinds a zone by name.- The OpenAPI document is served at
/api/v1/openapi.json, and/llms.txtdescribes the API for programs and agents.
2.9.8: stricter filters, compressed responses, simpler claims
- Filter values are checked. A value outside a filter's vocabulary (
filter[rank]=cultivar,filter[flower_color]=pink) answers400and lists the accepted values. It used to return200with wrong rows:filter[status]=foobarreturned the species without a status. Names are matched regardless of case. Arangewhose lower bound is above its upper bound answers400too, andfilter[light]=9now points you torange[light]=9,9. See Accepted values and errors. - Responses are gzip-compressed when the request sends
Accept-Encoding: gzip, which every browser and common HTTP client does. POST /api/auth/claimacceptsAuthorization: Bearer, as the reference already said, and returnsexpires_atin ISO 8601.expirationis deprecated. JWTs now count against the quota of the account that claimed them. See Client-side applications.- Pagination links stay reachable.
links.lastandlinks.nextstop at the deepest page you can request (page 2,500 at 20 per page) instead of pointing past it. Retry-Afteris readable by browser clients, next to theRateLimit-*headers.GET /api/v1returnsdetailed_plants_count; the misspelleddetailled_plants_countstays for now and is deprecated.- The serialization cache is keyed on the release. Records cached before 2.9.7 kept their old payload until now, so some of the 2.9.7 changes above only became visible everywhere with 2.9.8.
- Field descriptions were corrected:
minimum_root_depthis a rooting depth, not the soil depth a species needs, andnitrogen_fixationonly holdsHighorNone. See Plants fields.
