Skip to main content
The full technical notes behind the changelog, kept as published.

October 11, 2026: screening coverage classes, usage summary window, calendar office codes

Screening coverage.classes names the classes searched. GET /v1/screening can match classes from your goods_services text and search them too. coverage.classes.resolved now lists the classes matched from nice_classes plus goods_services; searched is the class filter applied by the class-filtered retrieval lanes (the containment lane, which finds marks that contain the name, is not class-filtered); and expanded lists the classes searched adds beyond requested. Before, a screen with nice_classes=16 and a coffee description searched classes 16 and 30 but reported resolved: [16], searched: [16] and expanded: []. Results, risk levels and verdicts are unchanged. Usage summary rows match billing_period. Without start_date and end_date, GET /v1/organization/usage/summary and the MCP get_usage_summary tool now list rows for the same window as billing_period: the current plan period, from the moment it started, the same period as credits_used. A period that started mid-day has a first row that starts at billing_period.start and holds only the spend after it. Before, an organization whose plan renewed mid-month got rows from its billing anchor day, including spend from the previous period, next to the new period’s credits_used. Calendar feed office codes. The portfolio deadlines calendar (.ics) names the office by its public code (US, EM), as the JSON deadline rows do. It said USPTO.

October 11, 2026: TypeScript SDK 0.22.0; MCP proceedings filters and compact results

MCP list_proceedings takes every filter of GET /v1/proceedings: party name (q), party_role, filed_date_gte/filed_date_lt, decision_date_gte/decision_date_lt, contested_class and aggregations, so an agent can ask for oppositions against a company in a date range. Cursors are bound to the new filters too. An unknown status, proceeding_type or party_role now returns validation_error; before, an unknown status or proceeding_type returned an empty page that read as “no proceedings”. MCP results are compact JSON, without indentation, so tool results cost agents fewer context tokens. The content is unchanged. TypeScript SDK 0.22.0 types everything the API added since 0.21.0: the deadline row numbers and warnings (on SignaList, so horizon_truncated reaches SDK users), office_class, the owner, attorney and firm trademark filters the API already accepted (sort, goods_services_text and more), the filing_route aliases on the rule catalogs and the designation_date filters. trademarks.search() sends request bodies up to 64 KB. Install it with npm install @signa-so/sdk@0.22.0 once it is on npm.

October 11, 2026: API contract fixes

OpenAPI contract. The spec now matches what the API sends:
  • request_id is optional on the four publicly cached single responses (GET /v1/offices/{code}, /v1/jurisdictions/{code}, /v1/classifications/{classNumber}, /v1/design-codes/{code}). They leave it out so a shared cache never hands one caller’s id to another; the cached lists already said so. Clients that validate responses against the spec no longer reject these.
  • Fields the API already sent are now declared: created_at and updated_at on proceedings, revoked_at on API keys, and attorneys with attorneys_has_more on firm detail requested with include=attorneys.
Rule catalogs accept trademark filing routes where the mapping is clear. GET /v1/deadline-rules accepts direct_national (read as national), direct_regional (as regional), and madrid_ir and madrid_designation (as madrid). GET /v1/opposition-rules accepts direct_national and direct_regional (as domestic). The other trademark values (transformation, divisional, unknown, and madrid_ir on opposition rules) still return 400 with the accepted list. The rule values keep working. Credit pricing. The read row of GET /v1/credits/pricing is per_request, which is how it is billed: one record, or one page of a list such as /v1/owners/{id}/trademarks. It said per_record. POST /v1/trademarks/batch, billed per submitted identifier, including the ones returned in not_found, carries unit: "per_record" on its endpoint entry. The rate limits page now shows a real RateLimit-Policy header, with both limits it lists. Swedish office links. office_url is null on Swedish (SE) trademarks, in detail, search and coverage rows. The link Sweden’s office used to serve (was.prv.se/VarumarkesDb) now ends at a page that does not exist. Deadline rows name the mark’s numbers. Rows of GET /v1/deadlines and GET /v1/portfolios/{id}/deadlines carry application_number, registration_number and ir_number, so rows of marks with the same name can be told apart and the rows of one international registration’s designations grouped. The calendar file puts the number in each event’s title and adds a URL link to the office record when the office serves one. A deadline already in its grace period is placed on the grace period’s last day, so its alarms are still ahead; before, it sat on the passed due date. Long lines are folded at 75 octets as RFC 5545 requires, and the calendar is named <portfolio name> deadlines. Deadline horizon warning. Deadlines are computed five years ahead. A due_before later than that on GET /v1/deadlines or GET /v1/portfolios/{id}/deadlines now returns warnings with a horizon_truncated entry naming the horizon date; before, the rows past the horizon were missing without a word. Coverage and billing period times. coverage_through on GET /v1/monitoring/status and on watch health is never later than the time of the response. Offices that publish whole days used to read “covered through the end of today” hours before the day ended. GET /v1/organization/plan and GET /v1/organization/usage report the same billing_period as GET /v1/organization/usage/summary: for an organization on credits, the window of its current plan credits, which is when they reset. Before, the plan and usage endpoints gave the anchor day at midnight. Classes as the office states them. Each entry of classifications on trademark detail carries office_class, the class as the office states it. A row with no Nice class now says what it is: US A and B (certification marks for goods and for services), US 200 (collective membership marks) or Spain’s 00. It is null on an international registration’s classes rolled up from its designations.

October 11, 2026: status counts add up, and France has a pending pipeline

Every stats count now sorts status stages into buckets from one table, so each status stage lands in exactly one bucket and the buckets add up to the total. Before, some stages were in no bucket.
  • Pending includes the opposition period. opposition_period records were in no bucket. They now count as pending. France’s office analytics pending_count goes from 1 to about 41,700, and market and class by_status.pending rise by the same records.
  • A pending cancellation is still registered. pending_cancellation records (about 3,800, all EUIPO) were in no bucket. They now count as registered, since the mark stays on the register until the cancellation is decided. registered_count and the grant rate change for the owners, attorneys and firms that hold them (including the per-firm grant rate on GET /v1/firms/{id}/attorneys), and for the EUIPO office (registered_count, registration_rate and the registered yearly trend).
  • New unknown_count. Records whose status stage is unknown (about 913,000, mostly WIPO and USPTO) now have their own count: unknown_count on office analytics, on the owner and attorney stats object, and on the analytics portfolio block, and next to by_status on market and class analytics, where it is null until those stats are next recomputed. With it, the bucket counts sum to total_marks (office, market, class), to mark_count (portfolio), or to the records counted (owner and attorney stats).
  • Attorney, firm and entity active_count rise. They now count opposition_period and pending_cancellation marks as active, as owner active_count already did. The analytics portfolio.active_count does the same, so active_count, dead_count and unknown_count add up to mark_count.
Party, office and entity counts update with the nightly stats run; market and class counts with their next recompute.

October 11, 2026: EU legs read EU everywhere; every country filter matches every spelling

Follow-up to “filters that match nothing now say so” below, so the same spellings behave the same on every endpoint.
  • Deadlines of EU legs. The WIPO record of a Madrid designation of the EU (stored by WIPO as EM) already read jurisdiction_code: "EU". Its deadline rows now read EU too: derived.next_deadline and derived.deadlines.items on trademarks, GET /v1/deadlines, portfolio deadlines, POST /v1/deadlines/compute (the item and its rows) and the reconcile computed context. Trademark and portfolio ETags change once.
  • Webhooks. The trademark.status_changed, trademark.corrected and office_action.issued payloads carry jurisdiction_code: "EU" for that record, where they carried EM, and so does trademark_event.territory_code on office_action.issued (and territory_code on GET /v1/trademarks/{id}/events). This is the same territory written the way the trademark row writes it, not a new meaning, so payload_version does not change. Events and deliveries stored before the change read EU too: GET /v1/events/{id}, automatic retries and POST .../redeliver all serve EU (the stored copy keeps EM).
  • Compute jurisdiction. jurisdiction on POST /v1/deadlines/compute reads EM as EU, UK as GB and WIPO as WO, as /v1/deadline-rules does, and the item answers with the code it was read as. UK and EM used to answer unsupported_jurisdiction. A code that is neither a country code nor known to the deadline rules (XX, ZZ) now fails only its own item, as an unknown ID does: a deadline_computation_error with id: null and error.code unknown_jurisdiction_code, while the other items are computed. deadline_computation_error.id can therefore be null. A real country with no modeled rules still returns unsupported_jurisdiction.
  • Country filters. owner_country on trademark search and on the owner, attorney, firm and entity trademark lists, country_code on /v1/entities, /v1/attorneys and /v1/firms, and a watch’s filters.ownerCountry (and the same filters on the MCP tools) now match every spelling, as country_code on /v1/owners does: EU and EM both match records stored under either, as do GB and UK. owner_country=EU used to miss the owners stored as EM. Any two-letter code is accepted, an empty value is no filter, and a value that is not two letters returns 400 unknown_country_code.
  • Trademark jurisdictions. jurisdictions=UK on trademark search, the party trademark lists, image search, /v1/screening, listing screening, /v1/compare and the MCP search tools is read as GB instead of returning 400 (or matching nothing), and WIPO as WO. jurisdictions=EM still returns 400 pointing at offices=EM: EM is EUIPO’s office code, and jurisdictions=EU already matches the EU legs WIPO stores as EM.
  • Watches. filters.jurisdictions reads EM as EU, UK as GB and WIPO as WO (["EM"] used to fail with no_live_office). Stored watch queries are not rewritten, but evaluation and preview now treat EU and EM as one territory: a stored watch with jurisdictions EU and WIPO in its offices may now alert on WIPO’s records of EU designations, which it missed before. filters.ownerCountry must be a two-letter country code or a list of them (400 unknown_country_code otherwise); an empty value is no filter, and a value a stored watch already holds is accepted on edit. Creating, previewing or editing a watch with an owner, attorney or firm ID that was merged into another now returns 400 naming the surviving ID to watch (owner own_X was merged into own_Y; watch own_Y). A merged ID a stored watch already holds is still accepted when you edit the watch, but that watch does not alert on the merged ID’s marks while WATCH_MERGE_FOLLOW is off (the default): point it at the surviving ID.
  • Cursors. A list cursor issued before this change for a request with a country_code or owner_country filter returns 400 cursor_expired once, because the filter now resolves to every stored spelling; restart from the first page.
  • search_meta.warnings[].code now documents all_words_required and multi_word_retry_skipped.

October 10, 2026: no restoration for Madrid designations, and nothing past an expired mark’s last renewal grace

Two corrections to maintenance deadlines on POST /v1/deadlines/compute, the deadline lists, derived on trademark records and POST /v1/reconcile. Both remove rows that were served in error, and one case gains a row: a live Madrid designation in its renewal grace now also shows its next international renewal, which the removed restoration row used to hide. On affected records derived.term, derived.expiry_date and derived.next_deadline change with them.
  • Madrid designations get no national restoration window. A designation of Japan, the UK, Singapore, India or Iceland was served a restoration row (jp_restoration, gb_restoration, …) after its renewal grace. Those remedies restore a national renewal, and a designation renews only at WIPO: Japan’s Trademark Act Article 68-22(1) and the UK’s International Registration Order 2008 disapply them for designations, and Singapore’s International Registration Rules, India’s Trade Marks Act section 36E(4) and Iceland’s Regulation 850/2020 do not extend them to designations. A cancelled designation is now served nothing (for example IR 2015-03-10, term end 2023-07-19: the row running 2024-01-19 to 2024-07-19 is gone), and an expired one only the international renewal while its six-month grace is open. National registrations keep their restoration windows. In GET /v1/deadline-rules every restoration rule now has applies_to: "domestic", so filing_route=madrid no longer returns them. Because no restoration row follows the grace any more, a live designation inside its grace period is shown the next international renewal, as designations of other countries already were.
  • An expired mark owes nothing past its last renewal grace. Once the grace period of an expired mark’s latest renewal whose window has opened has passed with no renewal on record, no row due after it is served, with or without a stated expiry_date. Before, a Philippine mark registered 2010-01-15 and expired was served, as of 2025-06-01, a declaration of use due 2026-01-15 for the fifth anniversary of a renewal that never happened. A renewal whose window is open is still served, and a renewal on record keeps the next term’s rows. On compute, an expired national mark with no renewal on record no longer lists the Philippine fifth-anniversary declaration in unsupported_rules.

October 10, 2026: POST /v1/trademarks accepts bodies up to 64 KB

POST /v1/trademarks accepts request bodies up to 64 KB, up from 8 KB, so an exclusion list of the documented 1,000 trademark_ids now fits in one search. Before, a body over 8 KB (about 190 ids) got a 413 before it reached the API. A GET query string is still limited to 2 KB (403), so send long lists by POST. Lien releases. Assignments gain release_match on GET /v1/assignments, GET /v1/assignments/{id} and GET /v1/trademarks/{id}/assignments: pointer when a release cites the security interest’s reel/frame, and null otherwise (always null for other conveyance types). A release now also cites a security interest when its text names the reel/frame (RECORDED AT R/F 1234/0567, REEL 1234/FRAME 0567, REEL NO. 1234 FRAME NO. 0567) and the release covers one of its marks; before, only the release_of_* fields counted. Owner and entity analytics (GET /v1/owners/{id}/analytics, GET /v1/entities/{id}/analytics) unreleased_security_interests and marks_with_liens use the same pairing, so both counts drop where a release cites its lien only in its text. Most USPTO lien releases cite no reel/frame, so these two counts can still include liens that were in fact released: only releases that cite their security interest are paired. Pairing uncited releases by lender, borrower and mark is planned. New recordings described with these citation forms, in the plural (“release of liens and security interests”), as “release by secured party” or as a bare “security agreement” are now classified as releases and security interests; recordings stored before this change keep their type for now. Owner list. GET /v1/owners no longer leads with “Redacted applicant (PRV #2)”, the placeholder Sweden’s office uses for applicants whose names it redacts. Placeholder owners are left out of the owner list, owner search and suggestions, as the docs already said. GET /v1/owners/{id} still answers for a placeholder owner, because the Swedish trademarks it holds link to it. Related owners. GET /v1/owners/{id}/related returns every relationship when paging. A related owner with two relationships (for example the direct and the ultimate parent) used to lose one of them at a page boundary. A cursor issued before this change returns 400 cursor_expired; restart from the first page.

October 10, 2026: screening no longer clears non-Latin marks; real coverage figures; compare flags self-comparisons

These changes apply to the alpha screening and compare endpoints.
  • Non-Latin marks need review. GET /v1/screening matches Latin text, but a mark written mostly in another script, such as НАЙК or 耐克, could come back clear because nothing matched. When a mark’s non-Latin letters, all scripts together, outnumber its Latin letters, the screen now reports coverage.language.supported: false and the main script in coverage.language.detected, and a would-be clear becomes needs_review with the unsupported_language warning. Accented and fullwidth Latin letters count as Latin. Found conflicts still band as before. Because the verdict gate changed for these marks, their screening_id changes too; screens of Latin marks keep their ids.
  • Coverage figures. coverage.horizon reported analyzed: 0 and cap: 0 on every screen. It now gives the conflicts analysed and the cap (200). capped is true when the overall horizon or a retrieval lane’s quota had more matches than it could analyse. A trademark_id screen sent without nice_classes or goods_services lists the record’s classes it searched in coverage.classes.resolved and searched instead of empty lists. coverage.lanes is reserved and stays empty.
  • Self-comparison. POST /v1/compare adds a self_comparison warning to a result whose trademark_id conflict is the candidate record or another record in its Madrid family. The risk level is unchanged.

October 10, 2026: owner, attorney and firm search lists the real name first

q on GET /v1/owners, GET /v1/attorneys and GET /v1/firms returns its matches in a new order. Before, a name that was only close to the query (a longer word that starts with it, a typo, two names run together) could rank above the party you searched for: q=nike on owners listed “nike”, “NIKEL” and “nikema”, with no trademarks, ahead of NIKE, Inc. Now a name that contains every word of the query gets a boost for its trademark count and ranks above typo matches, so among those names the party with more trademarks ranks higher. A name with a longer word that starts with the query can still rank high. Typos still match, lower in the list. The new order applies when sort is not sent. An explicit sort orders the matches by that field, as before, and so do owner searches with ticker, lei, publicly_traded or has_lei, which order matches by trademark count. One kind of match is gone on every order: a query word with a typo has to be close to a whole word of the name, and no longer matches a name that only starts with a similar word. A cursor issued before this release for a q list without sort can skip or repeat rows; start that walk again from the first page. The reference pages described q as a trigram or substring search. They now describe what it does.

October 10, 2026: filters from other endpoints return 400 instead of being ignored

A filter an endpoint does not support used to be ignored, so the answer looked filtered when it was not: GET /v1/analytics/market?offices=US returned the worldwide totals and GET /v1/deadline-rules?office=EM the whole catalogue.
  • Filters from other endpoints. A GET request with a query parameter the endpoint does not support, when that parameter is a filter on another endpoint (offices, office, jurisdiction, q, status, nice_classes, and so on), returns 400 with code unknown_parameter. The message names the parameter this endpoint has for it, if any: deadline-rules?office=EM says to use jurisdiction.
  • Common spellings. A few spellings no endpoint uses are rejected the same way: country, nice_class, query and trademark_ids.
  • watch_id on GET /v1/alerts. It never filtered that list; it now returns 400 pointing at GET /v1/watches/{id}/alerts.
  • Still ignored. Paging and shaping parameters (limit, cursor, include_total, sort, order, fields, include, format, language, page, per_page, offset) and other names no endpoint uses. Endpoints that already rejected unknown parameters, /v1/trademarks included, behave as before.

October 10, 2026: filters that match nothing now say so

Several filters matched nothing, with a 200, for a value that only differed in spelling or case from one Signa knows, or that was no code at all. These requests now return 400 validation_error with a hint, or are read the way you meant them. New 400 responses:
  • Jurisdiction codes. jurisdiction on /v1/deadline-rules and /v1/opposition-rules returns 400 for a value that is not a country or jurisdiction code, such as ZZ or USPTO. A real country with no data still returns an empty list, and historic Madrid designation codes the rules cover, such as YU or SU, keep working. jurisdictions=ZZ on trademark search also returns 400: ZZ is internal and was never a jurisdiction you could search. country_code on /v1/owners returns 400 only for a value that is not two letters; historical codes owners carry, such as DD or SU, keep working.
  • Fee catalog. GET /v1/fees?office= returns 400 for a value that is not an office or country code (XX, JPO). Other offices and countries still return an empty list.
  • Event types. event_type on GET /v1/trademarks/{id}/events and GET /v1/events returns 400 for an unknown type, listing the valid ones.
Read the way you meant:
  • Office spellings of a jurisdiction. EM is read as EU, UK as GB and WIPO as WO in jurisdiction on /v1/deadline-rules and /v1/opposition-rules. deadline-rules?jurisdiction=EM used to return only the Madrid renewal rule; it now returns the EU rules too. GET /v1/fees?office=UK now returns the GB fees.
  • Owner country. country_code on /v1/owners is case-insensitive and matches every spelling owners are stored under: EU and EM both return the owners recorded as either, as do GB and UK.
  • Event type case. event_type is case-insensitive: Renewal matches renewal.
  • EU legs of Madrid marks. With territory_match=direct, jurisdictions=EU now also matches the WIPO record of a Madrid designation of the EU, which WIPO stores as EM. That record’s jurisdiction_code now reads EU in every mode and on trademark detail, as territory codes already did, and the jurisdiction_code aggregation and the party analytics jurisdiction_spread count it under EU.
Better errors:
  • Every validation_error now carries an errors array. An error that is not about one field has a single entry with field (request).
  • A misspelt parameter on an endpoint that rejects unknown parameters gets a suggestion: stauts says to use status_stage.
  • A trademark number used as a trademark ID (GET /v1/trademarks/73120444) points at GET /v1/trademarks?q=73120444.
New warning: search_meta.warnings includes partial_owner_country_coverage when you filter by owner_country and EUIPO records are in scope. EUIPO publishes no owner country, so the filter matches no EUIPO trademark and EU trademark counts are missing from the result. Because the EU leg’s jurisdiction_code changed with no write to the mark, trademark and portfolio ETags change once: a client holding an older validator gets the new body with a 200 instead of a 304.

October 10, 2026: near_identical means about the same length; fewer look-alike rows for Cyrillic and Greek names

match.tier on GET /v1/trademarks read near_identical for a one-letter difference or a strong sound-alike even when the mark had more words than q: q=BRANDX labelled MARLON BRANDO and BRANDX ACTIVEWEAR near_identical. Such a match is q inside a longer mark, and is now similar, as the tier table says. Each name of a q list is measured against its own word count. Ranking and the rows returned are unchanged; only the label moves. The same tier gates watches: a watch with min_tier: near_identical no longer alerts on a mark that matches only this way, and alerts carry the new tier. A watch with min_tier: similar or weaker is unaffected. A q written only in Cyrillic or Greek letters, such as Кока-Кола, no longer runs the look-alike matches that allow a changed letter. Those matches folded the whole name into Latin letters and returned unrelated marks (KODA LUNA, KOGA PACE) as near_identical. Whole-mark look-alike matches still run (ВОТОХ written in Cyrillic still finds BOTOX), and a name that mixes Latin with Cyrillic or Greek letters keeps every look-alike match. Watches match the same way: an existing watch whose q is written only in Cyrillic or Greek letters stops alerting on marks it reached only through those matches, without being re-saved. Because these searches return different rows, search_meta.ranking_version is now v13, and a search cursor issued before this release is rejected once with 400 cursor_invalid: restart that search from its first page.

October 10, 2026: batch and reconcile find numbers written with separators; one IR number format

POST /v1/trademarks/batch and POST /v1/reconcile now find numbers written the way docketing systems export them. A number that finds nothing as sent is tried again with spaces, commas, periods, slashes and hyphens removed (and a leading WO removed from a batch ir_number), when what is left is a number: 73/273,292, 1,201,370 and WO1874500 find 73273292, 1201370 and IR 1874500, where they used to come back in not_found. A record stored with the separators still wins. On reconcile with verdict_detail: true, lookup.identifier_normalization is separators_removed when this happened, and lookup names the numbers looked up. A batch application number that more than one record shares now always answers the same record. ir_number on trademark rows (search, list, detail, batch and every party’s trademark list) and on assignment properties is now always the international registration number without leading zeros. USPTO, EUIPO and CIPO records of a Madrid registration used to show it as stored (0551089) while the WIPO rows showed 551089, so linking them by string equality failed. If you stored the zero-padded value for a US designation, match on the new value; the ir_number filters accept both forms, as before. Because the value changed with no change to the records, the trademark detail, portfolio and assignment ETags change once: a cached copy revalidates into a 200 with the new value.

October 10, 2026: search says when a name of several words found little

A q of several words on GET /v1/trademarks generally requires its words to appear in the mark, so q=stone lion capital does not find LION CAPITAL. Such a search that returns fewer than 5 rows in all now carries an all_words_required warning in search_meta.warnings (not with the phonetic channel, which also finds marks sharing one sound-alike word), with a ranked list of shorter phrases to send instead (q=["stone lion","lion capital"]). When Signa skips its second search for a multi-word name with no results (one that allows a one-letter difference in each word) because the first took too long, the response now carries multi_word_retry_skipped instead of saying nothing. Results are unchanged. The search docs and the MCP search_trademarks description now explain the rule.

October 10, 2026: reconcile no longer counts an empty register field as a mismatch

POST /v1/reconcile: a field the office does not publish at all now comes back with match: null instead of match: false, and it no longer counts toward mismatch_count or turns result into mismatch. That is the expiry and renewal due date at USPTO, which publishes neither, and the renewal due date at most other offices. A US mark sent with expiry_date or renewal_due_date used to read mismatch on every item, and now reads match when everything else agrees. A field the office does publish but this record lacks, such as the registration number of a pending application, is still match: false. match on fields[] is now boolean | null. With verdict_detail: true, field_verdicts still gives Signa’s computed date for those fields.

October 10, 2026: watch previews apply every filter; dead watch settings are rejected

Preview. On a busy office, a watch without a text query used to report every changed mark at the watched offices: a US class 25 watch, a class 46 watch and a watch on a made-up owner all previewed 167,817 with estimate_basis: "candidacy_upper_bound". Such a watch is now previewed like a text watch, with its filters as the search, so classes, owners, statuses and trigger_events apply. The count is exact, or estimate_basis: "lower_bound" when more than 10,000 marks matching the filters changed in the window. candidacy_upper_bound remains only for a watch scoped by offices or trademark IDs alone, or a time budget that ran out. When the search backend is down, such a preview returns 503 service_unavailable (retryable), as a text watch already did, instead of an unfiltered count. New 400 responses on create, PATCH, bulk create and preview:
  • a filters.niceClasses entry that is not a class from 1 to 45 (field query.filters.niceClasses[i]). A class sent as a numeric string, such as "25", is still accepted and stored as the number 25;
  • a filters.ownerId, attorneyId or firmId that is not a non-empty ID string, names no record, or names an owner Signa has retired.
Existing watches are not changed. A watch saved earlier with such a value keeps loading and evaluating, and a PATCH that sends the stored value back is accepted. A watch whose stored Nice classes include a value outside 1-45 now shows status: "degraded" with invalid_filter in its health.issues. Merged owners, attorneys and firms. Support for a watch to follow an owner, attorney or firm that is later merged into another record ships disabled: it is being rolled out behind a switch, and until it is on a watch matches the marks of the ID it names. The stored watch keeps the ID you saved either way. Diagnostics names a merge, with merge follow not enabled while it is off. Bulk create. A failed batch lists every failing item in one 400, and each errors[].field starts with the item’s index (watches[2].query.q). Before, only the first error came back, without an index. Diagnostics. reason now says when the change predates the watch, when the watch is paused (with the cause: paused, out of credits, or disabled) or has not evaluated the change yet, when a watched owner was retired, and otherwise mark did not match the watch query or filters (naming a merged owner, attorney or firm). It no longer returns no matching reason available. An unknown trademark_id on your own watch returns a 404 that names the trademark, not the watch. Attestation. In the month a watch was created, an office with no evaluations shows its gap from the watch’s creation, not from the start of the month, so the attestation no longer records a lapse before the watch existed. This changes content_hash for those periods. A period that ended before the watch was created, with no evaluations recorded in it, returns 422 period_before_watch.

October 10, 2026: Madrid renewal deadlines for zero-padded IR numbers

Some offices store an international registration number with leading zeros (0921642), while WIPO stores it without (921642). Signa missed the WIPO registration for those designations, so their renewal deadlines were anchored on the designation’s own date, or not computed at all. They now anchor on the international registration date, like every other Madrid designation. This changes the derived deadlines on trademark detail, batch and search responses, the deadline endpoints, portfolio deadline lists and calendar feeds, and /v1/reconcile for the affected designations: a few dozen EUIPO and CIPO records. No API behavior changed. These pages stated something the API does not do, or left out a limit that changes how to read a value:
  • US Section 71 deadlines. The guides named protection_grant_date as the trigger for US Madrid Section 71 and Section 15 deadlines. Signa computes them from registration_date. On the USPTO’s own 79-series record that is the date of the certificate of extension of protection, the date 15 U.S.C. 1141k sets for Section 71. A US designation row from WIPO’s records carries the date WIPO recorded instead, so docket from the USPTO record. With Compute Deadlines, send the certificate date as registration_date. See Deadline rules.
  • Compute Deadlines operative_date_basis. The office action fact’s operative_date_basis was described as defaulting to caller_supplied. It is required and has no default; omitting it returns 400.
  • US proceeding outcomes. Most ended US (TTAB) oppositions and cancellations read outcome: other, so a US win rate, including win_rate on owner and entity analytics, covers only cases decided on the record. The opposition guide, Search Proceedings and the analytics pages now say so.
  • Watch preview. The quickstart showed an exact count for a US class watch that the preview could not produce then: on a busy office it reported every changed mark at the watched offices. Since the same day’s preview change (see the entry above), preview applies the class filter there too, and the quickstart shows that. See Watches.
  • Record fields. filing_bases are the bases as filed; later changes are not reflected. legal_form is a normalized value (US LLCs map to corporation), not the form as filed. figurative marks can contain words in stylized lettering.
  • Search. The USPTO publishes no expiry date, so expiry_date_* never matches USPTO records, and renewal_due_date_* matches only USPTO Madrid extensions (79-series) carrying the international renewal date, never a domestic Section 8 or 9 date. A name written as one word (cocacola) does not find it split by punctuation inside a longer mark (COCA-COLA ZERO); search each spelling, or send mark_text_contains without q.
  • Analytics and liens. Office, market and class counts are trademark records, one per office record: a Madrid international registration counts for its own record, for each designation record, and again for any national office’s own record of a designation (such as a USPTO 79-series record). The office registration_rate is not reliable for GB. An unreleased lien can be a released one whose release cites no reel/frame. citation_issued can follow a final refusal whose text Signa has not extracted yet.
  • Portfolios. Managed marks count on the daily monitoring meter, free during the beta.

October 10, 2026: office_action.issued fires only for USPTO examiner actions

For USPTO marks, office_action.issued now fires only when the office issues an action, for example a non-final or final refusal, a suspension letter or inquiry, an examiner’s amendment or a post-registration audit action (63 USPTO codes in all). Before, 206 other USPTO codes that the office files under the same heading could raise it too: your own filings (a voluntary amendment or a response received), transactions with WIPO such as a grant of protection, suspension checks, abandonment notices and decisions on petitions (grants, denials, dismissals). A docketing system that opens a response deadline per event would have opened one for each. Those rows still appear on GET /v1/trademarks/{id}/events with the same event_type. An abandonment still raises trademark.status_changed. Other offices are unchanged.

October 9, 2026: US deadline corrections

Five corrections to US deadlines. All of them apply to every response from today, on trademark detail and search (derived), GET /v1/deadlines, portfolio deadlines and the calendar feed, POST /v1/deadlines/compute and POST /v1/reconcile.
  • WIPO records of US designations no longer show Section 71 or Section 15 deadlines. A WIPO record designating the US (office_code: "WO", jurisdiction_code: "US") showed us_madrid_declaration_of_use_s71_first, us_madrid_declaration_of_use_s71_at_renewal and us_madrid_declaration_of_incontestability_s15 dated from the WIPO registration date. The law runs them from the date the USPTO issued its certificate of extension of protection, which only the USPTO’s own record of the designation carries. Where the US is the home office of the international registration there is no US designation at all. These records now show no rows for those rules and list each of them in unsupported_rules with the new reason computed_on_office_leg. The USPTO record of the same designation keeps its rows, dated from the US registration date. If you imported these rows from WIPO records, remove them and use the USPTO record’s rows instead.
  • Supplemental Register registrations no longer show Section 15. The Section 15 declaration of incontestability is not available on the Supplemental Register (15 USC 1094), so us_declaration_of_incontestability_s15 no longer appears for a US registration whose register.type is supplemental. POST /v1/deadlines/compute takes an optional register_type (principal or supplemental) for the same result.
  • Extended response and statement of use deadlines are counted from the issue date. An extended Office action response deadline now runs six months from the Office action issue date, and each statement of use extension runs from the notice of allowance (37 CFR 2.62(a)(2), 2.89), so extended dates that landed after a short month move 1 to 3 days later, to the correct date. For example, an Office action issued 30 November 2025 and extended is due 1 June 2026, not 28 May 2026.
  • Maximum dates move off weekends and federal holidays. A deadline that reaches its maximum (the six-month response limit, the 36-month statement of use limit) on a Saturday, Sunday or federal holiday is now due on the next open day (37 CFR 2.196), with due_date_adjustment: "moved". Before, it was served on the closed day with not_checked. For example, a refusal of a Madrid designation sent on 25 June 2026 is due 28 December 2026, not on Christmas Day.
  • An unrenewed US registration shows its term ended. When a US registration’s renewal (the combined Section 8 and Section 9 filing) is not on record and its six-month grace period has passed, derived.term.state now reads renewal_not_on_record and derived.expiry_date is the term end that passed, instead of in_term with the next ten-year renewal. The next cycle’s renewal row is no longer shown. This applies only when Signa has the registration’s USPTO prosecution history, that history records at least one Section 8 or Section 9 filing (such as the six-year Section 8; a Section 15 filing does not count), and the USPTO status does not say the registration was renewed. For a past computation date, only filings and a status dated by then count. The USPTO keeps such a registration “registered” until it cancels it, usually within a few weeks; Signa’s status keeps the office’s value until then.

October 8, 2026: an attorney’s firms come from its filings

An attorney’s firm and address are now what its filings say. GET /v1/attorneys/{id} gains firms: the firms named on the attorney’s current filings, with id, name, trademark_count (the attorney’s trademarks filed with that firm) and latest_filing_date, most trademarks first, at most 20 (the firm in firm_id is added when it ranks lower). firm_id and firm_name on the attorney detail, and firm_name on GET /v1/attorneys, are now the firm on the attorney’s most recent current filing (by filing date) that names a firm, null when none does. Before, they were the firm on whichever filing first created the attorney record, which could be a firm the attorney filed with once, years ago: an attorney with thousands of filings could show a firm named on three of them. firm_id and firm_name on the detail are deprecated in favour of firms. address on the attorney detail is the address on the attorney’s most recent current filing that carries one, null when none does. For WIPO, Sweden and Italy attorneys, whose older filings were stored without an attorney address, the address the office holds for the representative is shown when no filing address is on record. GET /v1/attorneys?firm_id= lists the attorneys with at least one current filing that names the firm, so an attorney appears under every firm its filings name. Searching attorneys by q also matches the names of every firm on their filings once the attorney search index has been rebuilt, which follows this release; until then q matches the attorney’s name. The firms and the address are recomputed with the nightly statistics, so a filing that changes them shows up the next day.

October 10, 2026: a listed GLEIF ultimate parent passes its ticker to subsidiaries

An entity now inherits a listed company’s ticker when GLEIF reports that company as its ultimate parent, even when its direct-parent chain never reaches a listed company. Before, only the direct-parent chain counted, so an IP-holding subsidiary whose direct parent is an unlisted holding company carried no ticker. For example, NIKE INNOVATE C.V., which holds about 1,960 Nike marks, did not match ticker=NKE. What changes for such an entity:
  • Entities. Retrieve Entity shows a listing block with status: "subsidiary_of_listed", the ultimate parent’s ticker and LEI, publicly_traded: true, and the ticker in tickers. ticker= on Search Entities and Search Owners, and publicly_traded=true on Search Entities, match it.
  • The direct chain still wins. When the direct-parent chain reaches a listed company, that company stays the listed ancestor.
  • The newest ultimate parent counts. GLEIF reports one ultimate parent at a time. When older ultimate-parent records are still present, only the most recent one is used: if it is not listed, the entity gets no inherited ticker. If two or more different companies share the most recent start date, the entity gets none.
  • Timing. Listing data refreshes with the weekly GLEIF update, so these entities change after the first weekly refresh following this release. Entity search and detail, and owner search and detail, show the change the same day. The owner_ticker and owner_publicly_traded filters on trademark search and on watches follow within about a week, when the weekly public-company check refreshes each affected trademark.
  • Unchanged. Entity Family and include_family still follow direct parent and subsidiary edges only.

October 8, 2026: a filing shows only the firm it names

A trademark’s attorney now shows the firm named on that filing, and no other. Before, when a filing named no firm, Signa filled in a firm the same attorney was named with on some other filing. That borrowed firm could be a firm the attorney had never filed this mark through, so trademarks, search results and firm totals credited marks to the wrong firm. What changes:
  • Trademark detail and batch. attorneys[].firm_id and firm_name are the firm the filing names, and null when it names none. attorneys[].address is the address on the filing, and null when the filing has none. WIPO, PRV (Sweden) and Italian records never carry the address on the filing, so they keep showing the attorney’s address on file.
  • Madrid international registrations. The detail lists an attorney once per firm its designations name, each row with the territory_codes of the designations naming that firm. Designations that name the attorney with no firm get their own row with firm_id: null; they no longer take another designation’s firm.
  • Search. The firm_id filter and facet match only filings that name the firm. attorney_firm_name matches the firm name the filing states for its first (primary) attorney.
  • Watches. A watch filtered by firm_id or attorney_firm_name matches fewer marks once the search index is rebuilt: only the filings that name the firm.
  • Firm totals. trademark_count, active_count and the other counts on /v1/firms and /v1/firms/{id} count the filings that name the firm. attorney_count counts the attorneys on those filings. Firms credited through borrowed firms drop sharply: a firm that showed 5,031 trademarks can now show 3. A firm that no filing names has no counts.
  • Firm attorneys. GET /v1/firms/{id}/attorneys and GET /v1/firms/{id}?include=attorneys list the attorneys with at least one current filing that names the firm. Each row’s trademark_count, grant_rate and latest_filing_date cover the filings naming this firm, not the attorney’s whole portfolio, and the list is sorted by that count. firm_name is this firm’s name.
If you group or join trademarks by attorneys[].firm_id, expect more null values and smaller groups. A null firm means the filing names no firm. It does not mean the attorney practises alone. Search results and firm counts switch over after the next search rebuild and stats recompute. This supersedes the firm-of-record fallback described on October 4 and September 29.

October 7, 2026: renewal deadlines for Madrid designations without their own rules

A Madrid designation of a jurisdiction that has no deadline rules of its own now gets its renewal. That covers the EU designated through Madrid (WIPO’s code EM), Russia, Ukraine, Austria and 93 more codes in Signa’s data, historic ones such as DT, SU and YU included: about 3.2 million WIPO designation records, 2.1 million of them live. The EUIPO’s own records of Madrid designations of the EU (EU on the Madrid route) take the same rule. One new rule_id: madrid_designation_renewal, named “International Registration Renewal (Madrid designations)” in the catalog. The rule serves only codes WIPO designates: the WIPO Standard ST.3 codes of the 117 Madrid members (the EU as EM, Belgium, Luxembourg and the Netherlands as BX), the territories the Protocol extends to (Curaçao, Sint Maarten, Bonaire, Sint Eustatius and Saba, Guernsey, Jersey), and the historic codes WIPO’s register still carries (DD, DT, CS, SU, YU, AN). Any other code, UK or ZZ for example, stays unsupported_jurisdiction. The designation renews with the international registration at WIPO. Renewal is one payment there, it takes effect on the same date for every designation, and a later designation ends with the international registration (Madrid Protocol arts. 3ter(2), 6(1) and 7(1); Regulations Rules 30 and 31(2)). So the rule runs 10 years from the international registration date, or from the expiry WIPO states, with a window opening 6 months before the due date, a 6-month grace period against a surcharge, and due dates moved off WIPO’s closed days. Every value cites the Madrid texts, the WIPO Guide or the EUIPO guidelines with a verbatim quote and a pinned snapshot. These records now carry derived.expiry_date, derived.term with its grace_expiry_date, and the next renewal in derived.next_deadline. Before, derived.deadlines read supported: false with reason: "unsupported_jurisdiction" and derived.term.state read not_applicable. The rule’s rows carry the designated jurisdiction’s code (RU on a Russian designation). GET /v1/deadline-rules lists the rule once, under WO, and also returns it for ?jurisdiction= any code it serves. Points to know:
  • A Madrid designation of the EU, WIPO’s EM record or the EUIPO’s EU record on the Madrid route, is not served the EUIPO renewal (eu_renewal) or restitutio (eu_restitutio): the EUIPO does not handle renewal of international registrations designating the EU. On the EUIPO’s records this changes the rule, the consequence (lapse_of_international_registration), the calendar (wipo_geneva, so a due date on a EUIPO-only closure day such as 1 May no longer moves) and drops the restitutio row. Both EU rules now read applies_to: "domestic" in the catalog. EU trade marks filed at the EUIPO keep their dates; their rows’ last_verified reads 2026-10-07 and the EU sources no longer list the Madrid Protocol citation that covered the designation case.
  • On the EUIPO’s records of Madrid designations of the EU, each renewal row’s occurrence_key starts with the new rule_id (madrid_designation_renewal: where it read eu_renewal:), so it changes once. The portfolio iCal feed builds its event UID from that key, so a subscribed calendar sees each such event replaced once: the old event removed and a new one added. Any eu_restitutio event is removed.
  • POST /v1/deadlines/compute and POST /v1/reconcile apply the same rule to the items you send. {"jurisdiction": "EU", "filing_route": "madrid"} now returns madrid_designation_renewal where it returned eu_renewal (and no eu_restitutio row), and a Madrid-route item coded RU, EM or any other served code is now supported where it read reason: "unsupported_jurisdiction". The prosecution half (facts[]) is unchanged: an EU Madrid item keeps the EUIPO provisional-refusal rule (euipo_madrid_oa_response), and a jurisdiction without its own rules still reads unsupported_jurisdiction for every prosecution type, with no stated_deadline row served.
  • The schedule is the renewal only. Cabo Verde, Cambodia and Mozambique also require use declarations filed with their national office (WIPO Information Notices 27/2022, 11/2016 and 37/2016), which are not computed; every row of such a designation says so in its note, naming the notice.
  • A designation whose status stage is unknown (about 143,000 of these WIPO records, 49,681 of them Jersey) is served like any other record, with one exception: it is not credited a later expiry WIPO published for its international registration, because that renewal may have left it out. It keeps the term WIPO states for it, lapsed or not. On 7 October that held back 211 records whose family showed a later term. The same now applies to Madrid designations in jurisdictions with their own rules (16 records on 7 October).
  • A designation that WIPO reports refused, invalidated, surrendered, cancelled or expired past its grace gets no later renewal. One with neither an international registration date nor a stated expiry returns reason: "requires_office_date". National records of these jurisdictions, and every other jurisdiction that has its own rules, are unchanged.
See Madrid designations without their own rules. ruleset_version on derived changes once, so trademark detail and portfolio ETags change once on deploy. Maintenance rows are computed per request and need no reindex.

October 6, 2026: Portugal (INPI) deadline rules

New jurisdiction. PT now has a maintenance config, so GET /v1/deadline-rules, POST /v1/deadlines/compute and the derived block on a trademark answer for Portuguese marks. Two new rule_id values: pt_renewal, pt_renewal_madrid. Renewal runs 10 years from the FILING date (Código da Propriedade Industrial art. 247.º), with the fee due in the last 6 months of the term and a 6-month window after it against a surcharge; missing both ends the right (arts. 368.º n.º 6-7 and 36.º). That is pt_renewal, for national marks. A Madrid designation of Portugal has no Portuguese term to renew: the international registration is renewed at WIPO, so pt_renewal_madrid runs the same 10 years and 6-month windows from the international registration date (Madrid Protocol arts. 6(1) and 7(1), Regulations Rule 30(1)) and moves off WIPO’s closed days. Every value cites the Code, the Madrid texts or the INPI service page it comes from, with a verbatim quote and a pinned snapshot. Every Portuguese mark Signa holds today is a Madrid designation, about 78.7k marks. They now carry derived.expiry_date, derived.term with its grace_expiry_date, and the next renewal in derived.next_deadline. Before, derived.deadlines read supported: false with reason: "unsupported_jurisdiction" and derived.term.state read not_applicable. Two limits are documented rather than hidden. A national mark granted before 1 July 2019, when the current Code took effect, keeps the previous Code’s term, which ran from the grant (Decreto-Lei n.º 110/2018 art. 7.º n.º 2), and the text does not say whether its later renewals run from the filing anniversary or from the end of that term. Until INPI clarifies the transitional rule, such a mark, or one with no grant date filed before that day, returns supported: false with reason: "requires_office_date" unless the office’s term end is supplied. And no closed-day roll is applied to national dates: the Code’s periods are continuous (art. 27.º), so every adjustment reads not_checked. Madrid designations are affected by neither. See Portugal (INPI): Marks Granted Before 2019-07-01. ruleset_version on derived changes once, so trademark detail and portfolio ETags change once on deploy. Maintenance rows are computed per request and need no reindex.

October 6, 2026: class suggestion and goods and services on every plan

Suggest Classifications, Suggest Goods and Services and Validate Goods and Services are now available on Free. On a Free key, POST /v1/classifications/suggest, POST /v1/goods-services/suggest and POST /v1/goods-services/validate no longer return 403 plan_gated. Credit prices are unchanged: 10, 100 and 50 credits per request, spent from the plan’s monthly pool. Get Credit Pricing reports min_plan: "free" for all three.

October 5, 2026: rank many spellings in one search with a list in q

q on GET and POST /v1/trademarks and the MCP search_trademarks tool takes a list of up to 100 names, such as every spelling of a mark you are clearing. Each name runs through the same similarity channels in one search. A mark that resembles several names appears once, ranked by its closest name, and match.terms lists the names that found it. With include=match_details, match.details.terms gives each name’s own tier and channels.
  • Look-alikes are found. With lookalike, onyx also finds 0NYX (a zero for the O). Before, a list in q was an alias of mark_text_is, an exact filter, and missed such marks.
  • Limits. Up to 100 names when similarity is only identical and lookalike. With fuzzy, embedded or phonetic, including the default, up to 10 names and 30 words in total. More than 100 names returns 400 with code: too_big. More than 10 names or 30 words with those channels returns 400 with code: too_complex, naming the fix.
  • Same price. A list costs 10 credits per page, like any search.
  • Not a number lookup. A list is never read as a trademark number; use Batch Retrieve.
  • Pages are ranked across all names. A name with no hits on the pages you read is not proof that it is clear: page to the end, or search that name on its own.
  • Owner, attorney, firm and entity /trademarks lists take one search text; a list there returns 400.
Breaking: a list in q without similarity now runs the default channels, so a list over 10 names returns 400 until you add similarity=identical,lookalike, and its rows are ranked, with relevance_score. For an exact, letters-as-written filter over several spellings, send mark_text_is. A list with match=exact, starts_with, ends_with or contains returns 400. Cursors issued for a list before this change return 400 cursor_invalid. Removed: match_explanation and matched_terms on results, and search_meta.strategies_used and search_meta.match. Read match and search_meta.similarity_applied. See the migration guide.

October 5, 2026: owner list ticker and lei match the owner’s detail

GET /v1/owners?ticker= and ?lei= now match the tickers and LEIs Retrieve Owner returns. Before, they matched only the owner’s own company matches, so an owner linked to an entity was missing from ?ticker= of the ticker its detail showed.
  • ticker matches any of the owner’s tickers: its own SEC tickers or, when it has none, its entity’s (the members’ SEC tickers and the entity’s listing ticker, which can be inherited from a listed parent). This is how GET /v1/entities?ticker= matches an entity. The ticker on the owner’s detail is always one of them. Matching is case-insensitive.
  • lei matches any of the owner’s LEIs: its own GLEIF LEIs or, when it has none, its entity’s (the entity’s own LEI and the members’ LEIs). The lei on the owner’s detail is always one of them. Matching is case-insensitive.
  • A ticker on a GLEIF record is not one of the owner’s tickers, as on detail, so it no longer matches ?ticker=.
  • An owner whose entity is no longer served (GET /v1/entities/{id} returns 404) is matched on its own company matches only.
?publicly_traded= and ?has_lei= are unchanged: they read the owner’s own company matches, so for an owner linked to an entity they can disagree with the publicly_traded and has_lei its detail shows. No fields are added or removed.

October 5, 2026: MCP list_proceedings filters by party owner or entity

The MCP list_proceedings tool takes the party filters GET /v1/proceedings already supports: party_owner_id (own_...) returns proceedings where a party is linked to that owner, and party_entity_id (ent_..., alias entity_id) where a party is linked to any member owner of that entity. Validation matches REST: a malformed or wrong-type ID returns validation_error (or id_type_mismatch), an entity with more member owners than the cap returns entity_too_large, and an unknown entity returns an empty page. Parties without an owner link are not matched; use the REST q filter to match by name.

October 4, 2026: Deadline coverage for expired, cancelled and dead marks; reconcile names declined rules

  • Expired and cancelled marks name the rules they can still be served. A mark that has expired or been cancelled was registered, so a deadline that runs from the registration date (or, in Brazil and Mexico, the grant date) is owed when the mark’s status can still be served it. An expired mark is served any rule whose miss costs something while that rule’s window is open; a one-off declaration of a national mark (such as US Section 8, the Philippine third- and fifth-year declarations or the Mexican third-year declaration) closes before its term ends, so an expired national mark is not asked for its date, while a Madrid designation granted late in the term of its international registration still is. A cancelled mark is served only a renewal that opens a restoration window Signa models (EU, GB, IS, IN, JP, SG); of those renewals only Japan’s runs from the registration date, so a cancelled Japanese mark is the one that can lack it. With include_missed: true on POST /v1/deadlines/compute, and always on POST /v1/reconcile, both statuses also owe every rule whose missed cycle would be returned, provided some date the mark could carry would return its row as of the computation date (a US mark cancelled three years after filing owes no Section 8 or 9 date yet). A Mexican national mark registered before 10 August 2018 is never asked for its grant date for the third-year declaration, which covers later grants only; a Madrid designation still is, since its statement of grant can come years after its international registration. Before, such a mark with no registration_date or grant_date was reported as supported: true, and the rules it could not compute were not named. Now, when it owes such a rule and no rule can be computed, it reads supported: false with reason: "requires_office_date" on POST /v1/deadlines/compute and in derived.deadlines, and it is listed in unsupported_marks on GET /v1/deadlines and portfolio deadlines, as a registered mark with the same missing date already was. For example, the compute item { "jurisdiction": "US", "status": "expired", "filing_date": "2010-01-04" } returns supported: false. With "status": "cancelled" it stays supported: true with no deadlines, because the US models no restoration; add "include_missed": true and it returns supported: false, since its missed Section 8 and Section 9 cycles need the registration date. When some rule can still be computed, the mark stays supported and the owed rules it cannot compute are listed in unsupported_rules (and the mark in unsupported_marks). For example, a Philippine national mark with status expired, a filing date and no registration date lists ph_renewal, ph_declaration_of_use_renewal and ph_declaration_of_use_mid_renewal (and, with include_missed: true, ph_declaration_of_use_5yr, whose missed row would be returned). Send the registration date and those rules are computed; an office-stated expiry date anchors only the renewal.
  • A mark whose status ends every obligation is never declined. An abandoned Australian direct mark filed before 1996, a withdrawn Singapore direct mark filed before 15 January 1999, and a refused Madrid designation with no international registration date read supported: false with reason: "requires_office_date" on compute and in derived, while unsupported_marks left them out. They now read supported: true with no deadlines, like other abandoned, withdrawn, surrendered, invalidated or refused marks in a jurisdiction Signa models. A mark in a jurisdiction Signa does not model still reads unsupported_jurisdiction, and a refused WIPO international registration record keeps its renewal deadline, because a provisional refusal does not end the international registration.
  • POST /v1/reconcile names declined rules. With verdict_detail: true, computed now carries unsupported_rules, in the same shape as on POST /v1/deadlines/compute: the rules that apply to the record but were declined because it lacks the date the statute anchors them on. For example, a Philippine Madrid designation with no statement of grant of protection lists ph_declaration_of_use_5yr_madrid with missing_field: "protection_grant_date". Before, computed said supported: true with no trace of the declined rule, and a docketed deadline for it could not be told apart from one with no matching occurrence. The field is additive and is [] when nothing was declined. See Reconcile.
No served date moves: the first two changes decide only whether a mark is reported as supported and which rules it names as declined. ruleset_version on derived changes once, so trademark detail and portfolio ETags change once. No watch alerts or webhooks fire.

October 4, 2026: portfolio events include status corrections

When Signa corrects a status it published for a mark in one of your portfolios (for example a renewed mark shown as expired, or office records that reached Signa late and show the mark lapsing or a dead mark returning), you now receive a direct trademark.corrected event. No configuration change is needed:
  • Webhooks. Every endpoint subscribed to trademark.status_changed also receives trademark.corrected. The envelope type is trademark.corrected, so you can tell a correction from news. trademark.corrected is also accepted in enabled_events on its own (corrections only). Your stored enabled_events does not change.
  • Events feed. GET /v1/events lists trademark.corrected events by default, and, as on webhooks, event_type=trademark.status_changed includes them. event_type=trademark.corrected returns corrections only.
  • Payload. data is the trademark.status_changed body plus correction: { kind }, where kind is status or late_office_record. See trademark.corrected.
  • Watches are unchanged. A watch still receives trademark.corrected only when its trigger_events lists it.
The SDK adds TrademarkCorrectedData, TrademarkCorrection and TrademarkCorrectedEvent, and 'trademark.corrected' to WebhookEventType. A receiver with an exhaustive switch on the envelope type sees a new value.

October 4, 2026: firm counts follow the firm of record

Firm counts now count a filing under its firm of record. trademark_count, active_count and the other trademark counts on /v1/firms and /v1/firms/{id} count a filing for the firm named on it, else for the attorney’s firm. The firm_id filter and /v1/firms/{id}/trademarks use the same rule, but only on search documents built since it was added. Until the next full search rebuild, a firm’s trademark list can include filings counted for another firm and miss some counted for it, so its total can differ from trademark_count. attorney_count still counts the firm’s own attorneys: a firm whose attorneys file only under other firms of record keeps its attorney_count, with trademark counts of 0. The new counts appear after the next nightly stats run.

October 4, 2026: a linked owner’s ticker and LEI come from its entity

GET /v1/owners/{id} now serves a linked owner’s company facts from its entity, the way GET /v1/entities/{id} returns them. Before, owner detail combined only the members’ company matches. An owner could show another LEI, no ticker or publicly_traded: false while its entity showed the entity’s own LEI, a listing ticker and publicly_traded: true.
  • publicly_traded and has_lei equal the entity’s. publicly_traded is also true when the entity is itself listed or is a subsidiary of a listed company.
  • ticker is the owner’s own first SEC ticker. When it has none, it is the entity’s ticker, which can be a ticker inherited from a listed parent.
  • lei is the owner’s own first GLEIF LEI. When it has none, it is the entity’s lei: the entity’s own LEI when set, else the first member LEI.
  • companies[] lists the same matches, the owner’s own first.
  • When the entity was merged into another, the facts are the surviving entity’s. When the entity is no longer served (GET /v1/entities/{id} returns 404), the owner reports only its own matches and companies_source is direct.
  • GET /v1/owners/{id}/related walks the one lei the owner’s detail shows: its own first LEI, else its entity’s. An owner with several LEIs of its own used to walk all of them, and an owner with none walked nothing.
  • Owners not linked to an entity are unchanged. The MCP get_owner and get_owner_related tools return the same values. See Retrieve Owner.
Owner, attorney, firm and entity detail ETags change once. An owner’s ETag now also changes when its company facts or companies[] change, for example when its entity’s listing changes. No fields are added or removed, and no webhooks or watch alerts fire.

October 4, 2026: status corrections arrive as trademark.corrected; status basis relabels raise no alert

trademark.corrected, an opt-in watch trigger event, used to fire only when a retracted record reappeared. It now also carries status corrections, so watches that did not opt in are not alerted about old news:
  • A status Signa corrects. When Signa fixes a status it published wrongly, for example a mark shown as expired that the office records as renewed, the status change arrives as trademark.corrected instead of trademark.status_changed or trademark.updated.
  • Late office records. When office records reach Signa late and show a mark lapsing, or a dead mark returning, the change arrives as trademark.corrected too.
  • Other changes in a correction raise no alert. Any other change Signa stores while correcting statuses or catching up on late office records, including marks Signa first learns of from late records, updates the mark but raises no alert.
  • Status basis relabels raise no alert. A change that only relabels where a status comes from (status.basis, for example office to computed) no longer raises a trademark.updated alert. The mark shows the new basis.
  • MCP. The signa_alerts_list tool’s event_type filter now accepts trademark.retracted and trademark.corrected, like GET /v1/alerts.
To receive corrections, add trademark.corrected to a watch’s query.trigger_events. For portfolio marks, corrections now also arrive as direct trademark.corrected events (see the entry above). No request or response fields change.

October 4, 2026: derived.term and no projected term past a lapsed expiry

When the expiry an office states had passed its grace period (and restoration window) with no renewal on record, derived.expiry_date showed the next cycle ten years on, with a renewal “due” then. A UK mark surrendered in 2014 with a 2024 expiry showed 2034; a French mark whose 2026-02-05 term ended in August showed 2036. The term on record now ends where the office’s record ends it, and a new block says where it stands.
  • New derived.term on trademark detail, batch lookup, search results, portfolio rows, watch previews and the MCP get_trademark tool: state (in_term, in_grace, in_restoration, renewal_not_on_record or not_applicable), grace_expiry_date, restoration_expiry_date and renewed (whether a renewal on record began the term). See The term on record.
  • derived.expiry_date stays at the office-stated term end once it has passed, while the mark can be renewed late or restored and, with term.state: "renewal_not_on_record", after that. While a restoration window is open it is that date (it was null). A renewal the office recorded (including one recorded after the grace period), or for a Madrid designation (a national office’s record, IP Australia’s for example, or WIPO’s own) an expiry WIPO published for the international registration in a later term, moves it forward to the next term, which reads in_term. The rows of that designation keep the office’s own dates as their trigger.
  • No renewal is computed past such a term end. derived.deadlines.items and derived.next_deadline drop the projected later cycles and the restoration of a cycle that never began. The same applies to GET /v1/deadlines, portfolio deadlines and the iCal feed, POST /v1/deadlines/compute and POST /v1/reconcile, whose computed expiry_date is now the lapsed term end.
  • An office that reports a mark expired the day after its term ends (the UK office does) reads in_grace, then in_restoration, until those windows close.
  • status and the top-level expiry_date are the office’s and do not change. A schedule with no office-stated expiry (every USPTO record) keeps the statutory term end.
ruleset_version on derived changes once, and every detail and portfolio ETag changes once (the block has a new key). No watch alerts or webhooks fire.

October 3, 2026: China Madrid opposition windows from 2027; Philippine and Mexican office closures

  • China, Madrid designations: two months from the WIPO publication from 2027. CNIPA published draft transitional measures for the revised Trademark Law for comment on 28 September 2026. They are not in force yet. Under the draft, an international registration whose WIPO Gazette date is on or after 1 January 2027 gets the revised two-month opposition period counted from the publication. The draft does not say whether the current start, the first day of the month after the Gazette, survives, so cn_opposition_madrid serves those registrations the window both readings allow: it opens on the first day of the following month and closes two months after the Gazette date. For a Gazette date of 15 January 2027 the window is now 1 February to 15 March 2027, where it was 1 February to 30 April. Registrations published before 2027 keep three months from the first day of the following month. The shorter window is served first because a close that turns out early costs an opponent nothing, while one that turns out late costs the right. If the final measures differ, the rule follows them. On GET /v1/opposition-rules the rule now has window_change_date: "2027-01-01", window_months: 2, window_starts_on: "day_after" and the new field window_opens_on: "first_of_following_month" (null on every other rule), and the earlier era moved to window_months_before: 3 and window_starts_on_before: "first_of_following_month". The draft measures and the consultation notice are among its sources. See opposition rules.
  • Philippines: IPOPHL closed on 16 to 18 November 2026. Proclamation No. 1447 declares those days non-working in Metro Manila, where IPOPHL has its office. A Philippine opposition window that closed on 14 to 18 November 2026 now closes on Thursday 19 November 2026, with close_adjustment: "moved".
  • Mexico: four IMPI suspensions of time limits. IMPI suspended all its time limits on 8 and 9 August 2024, 18 May 2026, 23 September 2026 and 25 September 2026, by notices in the Diario Oficial de la Federación. Mexican opposition windows and renewal deadlines that fell on those days now move to the next working day. GET /v1/deadline-rules lists the four notices among the Mexican sources.
The Philippine and Mexican corrections only move dates later, so nobody who acted on the earlier date acted late. The Chinese change moves closes earlier, but only for Gazette dates from 1 January 2027, so no affected window has opened yet. ruleset_version on derived changes once, so trademark detail and portfolio ETags change once. Opposition windows stored in search for Philippine and Mexican marks are recomputed after this release, so for a short time search results can still show the earlier close. No watch alerts or webhooks fire.

October 3, 2026: proceedings party owner and entity filters return linked proceedings

Proceeding parties are now linked to owners. A party is linked to an existing owner when the marks in the dispute show which owner it is and the names match with the same company suffix. This covers USPTO, CIPO and IP Australia proceedings, and new proceedings are linked daily.
  • party_owner_id, party_entity_id and entity_id on GET /v1/proceedings return results. They match proceedings where a party is linked to the owner, or to any member owner of the entity. Combined with q or party_role, every filter still has to match the same party.
  • Parties without a link are not returned by these filters. They include most Canadian and Australian opponents (they are matched only against the owner of the mark under challenge), a name that matches only without its company suffix, and a recorded name that lists several parties. Search with q to match by name or for complete coverage. See Search Proceedings.
  • parties[].owner_id on proceedings now carries the linked owner, reported as its current owner record (the surviving owner if it has since been merged), and stays null for a party without a link.
  • Owner and entity analytics count challenger disputes. litigation.as_challenger on owner and entity analytics counts the disputes where a linked party is the opponent or petitioner, so it is no longer always 0. proceedings_total changes with it.
A proceeding’s detail ETag changes whenever a party’s link is added, moved or cleared: first for the proceedings linked with this release, then as the daily sweep updates links. The sweep can later move a link to another owner or clear it, so parties[].owner_id is not fixed once set. No webhooks or watch alerts fire for link changes.

October 2, 2026: USPTO post-registration office actions get their response deadline

When the USPTO mails a post-registration office action on a Section 8, Section 71 or combined Section 8 and 9 filing, the mark now carries a deadline to respond. Before, the filing closed its cycle and nothing replaced it, so a registration that will be cancelled without a response within weeks showed its next renewal, years away, as derived.next_deadline.
  • New row type post_registration_oa_response (rule_id: "uspto_post_registration_oa_response"), due six months after the action or at the end of the filing period the action examined, whichever is later, moved off weekends and federal holidays. It appears in derived.deadlines and derived.next_deadline on trademark detail, batch lookup, search results and portfolio rows, on GET /v1/deadlines (new type=post_registration_oa_response filter value), on portfolio deadlines and the iCal feed, on POST /v1/deadlines/compute for stored trademark ids, and on the MCP get_trademark tool. occurrence_key is uspto_post_registration_oa_response:<action date>:<action code>.
  • New optional note field on deadline rows. Present only when the record adds something the dates do not say: the action a response row answers (PRA8 2026-04-19), a “no response required” notice, or a prosecution history that could not be read.
  • The row closes only on explicit evidence: a response naming the action’s section, the office’s acceptance of the examined filing, or a cancellation of it. A notice of incomplete response reopens every row it could concern. If the response date passes with nothing on record, the row stays as missed; the examined declaration or renewal row is not changed. Whether the registration was lost is read from its USPTO status.
  • When the record cannot settle the date (the examined filing is not on record, a notice of incomplete response has no action on record, or the action predates 2015), the row stays open on the earliest date Signa can defend, with a note to check TSDR. A served date never moves later.
  • An action still open more than a year after its response date, on a registration whose current status is registered, is treated as resolved by the USPTO: no row.
  • On POST /v1/deadlines/compute for a stored id, prosecution_deadlines now dates this rule from the stored history, and support reports it as computed instead of facts_required. due_date is six months from the action, as on caller-supplied facts, and effective_due_date is the date the row serves. A closed one carries closed_by: "response", or the new value closed_by: "acceptance" when the office accepted the examined filing, with closed_by_fact_id: null (the closing entry is named in notes).
  • GET /v1/deadline-rules and the MCP get_deadline_rules tool list the rule. See USPTO post-registration office actions.
ruleset_version on derived changes once, so trademark detail and portfolio ETags change once. SDK clients with an exhaustive switch on type see a new value. No watch alerts or webhooks fire.

October 1, 2026: records from offices that are not live yet are no longer served

Signa ingests some offices before they go live. GET /v1/offices already left those offices out, but their trademark records were still returned. They are now absent everywhere a customer reads trademarks, until the office goes live and appears on GET /v1/offices:
  • Search and list. GET and POST /v1/trademarks, in both grouped and expanded views, leave these records out of rows, pagination.total_count and aggregations. The same applies to GET /v1/trademarks/suggest, screening, image search, the owner, attorney, firm and entity trademark lists, and the MCP search and list tools. An office number or a tm_ id in q does not return such a record.
  • Lookups by id. GET /v1/trademarks/{id} and its events, proceedings, assignments, documents, citations and cited-by sub-resources return 404. POST /v1/trademarks/batch lists the id in not_found. GET /v1/deadlines?trademark_id=, POST /v1/deadlines/compute, POST /v1/compare and screening by trademark_id treat the record as not found. The MCP get_trademark, batch_get_trademarks, get_trademark_events and get_trademark_proceedings tools answer the same way.
  • International registrations stay. A WIPO international registration is a record of a live office, so it is still returned with all of its designations, including designations of a country whose national office is not live yet. The national office’s own record of that designation is not returned on its own. Image search matches images by their own record’s office, so an international registration whose only image sits on such a national record is not found by image search.
  • Unchanged. offices= and office_code filters naming an office that is not live still return 400 with unknown_office_code. jurisdictions= with such a country still returns the rights of live offices that protect it, such as EU trade marks and Madrid designations. Marks already in a portfolio stay in it, are listed, and keep their portfolio deadlines.
Responses for records of live offices are unchanged, and so are their ETags. No webhooks or watch alerts fire.

October 1, 2026: proceedings q matches the party you filter by; party owner filters return no results (superseded October 3, 2026)

  • Behavior change. On GET /v1/proceedings, q and party_role now have to match the same party. q=Acme&party_role=opponent returns proceedings where a party named Acme is the opponent. Before, it also returned proceedings where Acme was the respondent and anyone else was an opponent, so the list could include cases from the wrong side. q combined with party_owner_id or party_entity_id follows the same rule. q alone and party_role alone are unchanged.
  • party_owner_id, party_entity_id and entity_id return no results today. Proceeding parties keep the name the office recorded but are not yet linked to owner or entity records, so these filters match nothing. They stay accepted. Search by name with q, which matches a case-insensitive substring of the recorded party name; it does not add related companies or subsidiaries. Search Proceedings and the opposition guide now use q in their examples. Superseded October 3, 2026: these filters now return proceedings whose parties are linked; see that entry.
  • The party_role aggregation still counts every role on the matching proceedings, so q=Acme&party_role=respondent can show an opponent bucket: it counts the cases that had an opponent.

October 1, 2026: Australia, Norway, Sweden and Singapore show as covered on /v1/jurisdictions

GET /v1/jurisdictions, GET /v1/jurisdictions/{code} and the MCP list_jurisdictions and get_jurisdiction tools returned office_code: null and office_status: "not_covered" for AU, NO, SE and SG, although their offices are live on GET /v1/offices. They now return office_status: "live" with office_code AU, NO, SE and SG. ES now returns office_status: "roadmap", like the other offices that are planned. No other jurisdiction changed.

October 1, 2026: USPTO declarations and renewals on record close their deadlines

Deadlines for USPTO marks now read the Section 8, Section 15, Section 71 and Section 8 and 9 filings in the mark’s prosecution history. Before, a declaration the USPTO had already accepted was still served as in_grace and then missed, a US designation under the Madrid Protocol with both Section 71 affidavits accepted showed both as missed, and a renewal filed on time showed as in_grace.
  • A filing made inside its window (from the day the window opens to the end of the grace period) closes that cycle on derived.deadlines and derived.next_deadline on trademark detail, batch lookup, search results and portfolio rows, on GET /v1/deadlines (including urgency=missed), on POST /v1/deadlines/compute for stored trademark ids, on portfolio deadlines and the portfolio iCal feed, on POST /v1/reconcile and on the MCP get_trademark tool.
  • The combined Section 8 and 9 renewal closes only when both parts are on record.
  • derived.expiry_date and the term end POST /v1/reconcile compares against move to the next term only when the USPTO accepts the renewal, not when it is filed.
  • A Section 15 declaration whose window has passed is no longer listed as missed (urgency=missed, include_missed). Section 15 is optional and can be filed after any later five-year period of continuous use, so nothing is lost. An open Section 15 window is still served.
  • A US designation ingested from WIPO’s records is not covered yet. See USPTO filings already on record.
ruleset_version on derived changes once, so trademark detail and portfolio ETags change once. No watch alerts or webhooks fire.

October 1, 2026: offices declare proceedings support; proceedings come only from those offices

Every office on GET /v1/offices, GET /v1/offices/{code} and the MCP list_offices and get_office tools now carries capabilities.proceedings: available when Signa ingests and serves the office’s oppositions, cancellations and appeals, in_progress when a pipeline is being built, and not_available otherwise. See List Offices.
  • GET /v1/proceedings and the MCP list_proceedings tool with an office_code for a live office whose capabilities.proceedings is not available return 422 capability_not_available, with capability, capability_state and office_code in the error. No query runs and no credits are charged. Before, such a request could time out, or return an empty list that looked like “this office has no proceedings”.
  • A proceeding_type that no served office records (today court_action), or that the requested office_code does not record, returns an empty page and empty aggregations buckets straight away, charged as a normal page. Search Proceedings lists the types each office records.
  • The proceedings endpoints return proceedings only for offices whose capabilities.proceedings is available: the GET /v1/proceedings list, GET /v1/proceedings/{id} (a proceeding from any other office is 404), GET /v1/trademarks/{id}/proceedings, the proceedings_count on a trademark’s detail, and the MCP get_proceeding, list_proceedings and get_trademark_proceedings tools. Two signals catch up after this release:
    • aggregations counts on GET /v1/proceedings may still include proceedings held for offices that are not live yet, until a follow-up backfill completes. The listed proceedings never include them.
    • Search and screening signals that come from the search index (the has_proceedings filter, the ranking boost for marks with proceedings, and screening’s prior-proceedings and litigious-owner signals) apply the same rule to each mark when it is next indexed. Until then, an international registration whose only proceedings sit on a designation in an office that is not live yet can still match has_proceedings=true.
  • The GET /v1/offices and GET /v1/offices/{code} ETags change once, because the body gained a field.

October 1, 2026: any API key can connect to MCP

The MCP server at /mcp (and /mcp2) now accepts every valid API key and OAuth token, whatever its scopes. Before, a key needed one of read, search, trademarks:read, billing:read, portfolios:manage or admin to connect at all, so a key with only events:read got 403 and could not call signa_events_list or get_account.
  • initialize and tools/list work for every session. tools/list returns every tool, including ones the session can’t call.
  • get_account and get_credit_pricing work for every key.
  • A tool the key lacks a scope for returns the forbidden error REST returns (status 403, naming the scope) with the call’s request_id, and is not charged.
  • An invalid, revoked or expired credential still gets 401. Rate limits and the batch cap are unchanged.
See MCP scopes.

October 1, 2026: deadline corrections for lapsed marks and Swiss, Polish and Norwegian opposition windows

  • A lapsed mark is no longer served a renewal ten years out beside its restoration window. Some offices keep a mark at registered for months after its stated term ended. When the office states a term end that has passed and a restoration window is on the schedule, derived.deadlines on trademark detail, GET /v1/deadlines, POST /v1/deadlines/compute and POST /v1/reconcile now serve the lapsed renewal while it is in grace and the restoration window, but no later renewal cycle. After the grace period, and while the restoration window is open, derived.expiry_date is null. The office’s status and expiry_date are unchanged. A mark the office has renewed, or whose stated term end is still ahead, is not affected. See Restoration periods.
  • Switzerland: no opposition window before the Trade Mark Protection Act. Opposition in Switzerland exists since the Act commenced on 1 April 1993 (MSchG art. 79). A Swiss publication dated before that day, national or Madrid, now has no window instead of a three-month one. A national mark filed before that day has none either, whatever its publication date (MSchG art. 76(2)(c)); this needs the filing date, which trademark detail uses and which POST /v1/oppositions/compute reads from filing_date.
  • Poland: no opposition window before pre-grant opposition existed. Pre-grant opposition in Poland began on 15 April 2016 (Dz.U. 2015 poz. 1615 art. 3). A national publication dated before that day, or a national application filed before it (art. 2 ust. 1 of the same Act), now has no window instead of a three-month one. Madrid designations of Poland were already gated at that date.
  • Norway: two months for registrations published before 1 July 2010. The repealed 1961 Trademarks Act § 21 gave two months from publication, so the window for a registration published before 1 July 2010 now closes one month earlier and cites that Act. Every window in that group closed years ago.
  • New reason before_commencement on POST /v1/oppositions/compute. When an opposition rule exists for the office but the item was published, or filed, before the date the rule applies from, the item now returns reason: "before_commencement" with the rule’s rule_id and effective_from. Before, it read unsupported_office, which suggested no rule existed for the office. The same applies to rules that already had a start date, such as Vietnam’s and Mexico’s. unsupported_office now means only that no rule exists for the office and route. Trademark detail is unchanged: derived.opposition_window.reason keeps unsupported_office for these records.
GET /v1/opposition-rules shows the new applicable_from_date and effective_from values on ch_opposition, ch_opposition_madrid and pl_opposition, the era fields on no_opposition, and the added sources. ruleset_version on derived changes once. Trademark detail and portfolio ETags change once. Opposition windows stored in search for Swiss, Polish and Norwegian marks are recomputed after this release, so for a short time search results for those marks can still show the earlier window. No watch alerts or webhooks fire.

October 1, 2026: MCP search tools take date ranges and field projection

search_trademarks and list_trademarks now accept every date filter that GET /v1/trademarks has, in the POST range shape: filing_date: {"gte": "2024-01-01", "lt": "2025-01-01"}, and likewise registration_date, expiry_date, renewal_due_date, publication_date, status_effective_date, priority_date, first_use_anywhere_date, first_use_in_commerce_date, termination_date, updated_at and family_updated_at. They also accept fields and include, which project rows as on REST; id and object are always kept. Validation is REST’s: conflicting bounds or an unknown field return validation_error, and the call is not charged. include: ["match_details"] on list_trademarks adds match.details, as it does on GET /v1/trademarks. See MCP tools. One REST change comes with this. On POST /v1/trademarks, a date range with no bound, such as "filters": {"filing_date": {}}, is now ignored like an absent range. It used to reach the search as an empty filter, which forced one row per record (an expanded_fallback warning) or returned 400 when international_registrations was grouped. A cursor from such a request now returns cursor_invalid; restart from the first page.

October 1, 2026: documentation corrected against the API

No API behavior changed apart from the harmonised_only parameter description. These pages said more than the API does:
  • Freshness. Trademark detail reads were described as strongly consistent. They carry Cache-Control: private, max-age=300, so a cached detail read can trail a write by up to five minutes, and they may be served from a database read replica. See Data Freshness.
  • Search depth. Not every search stops at 10,000 rows: a grouped request without q pages by key, with no fixed depth. A position walk can repeat or skip a row when records change between pages, so deduplicate on id. See Search depth.
  • Harmonised terms. is_harmonised: true marks a term from a harmonised list (the EUIPO Harmonised Database, or a TM5-harmonised USPTO ID Manual entry). It does not mean every TM5 office accepts the wording; read accepted_offices. The harmonised_only description on GET /v1/goods-services and the MCP tool now says the same.
  • Entity portfolios. GET /v1/entities/{id}/trademarks returns the marks of owner records linked to the entity, and include_family=true adds GLEIF-reported subsidiaries. Neither is a complete-portfolio guarantee.
  • Trademark events. USPTO timelines include the office’s e-mail notifications as their own office_action events; EUIPO timelines are publication events, not a lifecycle history. See Trademark Events.
  • Restoration rules. The EU’s restitutio in integrum rule (eu_restitutio) is one of the restoration rules in GET /v1/deadline-rules; the reference listed only the others.
  • Guides no longer state jurisdiction counts for deadline and opposition rules. GET /v1/deadline-rules and GET /v1/opposition-rules are the current lists.

October 1, 2026: a TTAB interlocutory order is no longer a proceeding’s decision

On US proceedings, an interlocutory order of the Trademark Trial and Appeal Board, such as a ruling on a motion to compel, suspend or amend, no longer counts as the proceeding’s decision: it sets no decision_date or decision_outcome and does not change status or outcome. Before, such an order could be stored as the decision, so a proceeding that was still running showed a decision_date and a duration_days. Only orders recognised as interlocutory change. Every other TTAB ruling, including a summary judgment that sustains an opposition and an order that vacates a decision, is handled as before. Affected proceedings are corrected in place and their ETags change once.

October 1, 2026: owner and entity names show accented characters

Some owner names came from office feeds with HTML character references still in them, so &#352;KODA INVESTMENT a.s. showed instead of ŠKODA INVESTMENT a.s.. The API, MCP tools and webhooks now decode these references when they return a name:
  • owners[].name on trademark rows and trademark detail.
  • name, name_original_script and aliases[].name on owners, and the names on /v1/owners/{id}/related.
  • Entity names, member names and family names.
  • Attorney client names, proceeding parties[].name and assignment parties[].name.
  • trademark.owner_name on alerts and alert.created webhooks, and subject.name on party analytics.
canonical_name is unchanged. trademark.status_changed event payloads keep owner_name as it was recorded. Stored records are not rewritten, so no webhooks or watch alerts fire. owner_name filters, on search and on watches, find a record by its decoded name as well as by the name the office sent, including names where only some characters were escaped. Names escaped with other named references, such as &apos; or &nbsp;, may still need the name as the office sent it. owner_id stays the exact way to filter by owner. ETags on trademark, portfolio, owner, attorney, firm, entity, proceeding and assignment detail change once, so a cached body revalidates to the decoded name.

October 1, 2026: MCP errors match REST; proceedings cursors are bound to their query

MCP tool errors now carry the same JSON error body as the REST API, plus the call’s request_id. See MCP errors.
  • A database statement timeout is timeout (504, retryable). It used to read “invalid or malformed ID”.
  • A lost database connection, failover, or overloaded search cluster is service_unavailable (503, retryable).
  • Any other server failure is internal_error with a reference_id. Database and search-engine messages no longer appear in tool results.
  • Invalid arguments and unknown tool names return validation_error and not_found bodies instead of plain text. errors[] names each field.
  • A preview_watch that runs out of time returns preview_timeout (504), as POST /v1/watches/preview does.
  • get_account works for any key that can connect to MCP, not only keys with billing:read. Without billing:read it returns identity with plan: null.
  • list_trademarks and list_proceedings with only blank filters ("", " ", []) return validation_error without running or charging.
  • search_trademarks, list_trademarks and the party trademark tools reject an unknown status, status_stage or jurisdiction code instead of matching nothing.
  • A JSON-RPC batch of more than 10 messages in one POST is rejected with JSON-RPC error -32600.
  • A body that is not valid JSON or not a JSON-RPC message, or a request with malformed method parameters, returns a fixed JSON-RPC error with error.data.request_id, instead of the parser’s error text.
GET /v1/proceedings and list_proceedings cursors now carry the filters and sort that produced them. Reusing a cursor with a different filter or sort returns cursor_invalid, and an empty cursor returns cursor_expired. A cursor issued before this change is rejected with cursor_invalid; start the list again.

October 1, 2026: Benelux, Malta and OAPI member states resolve on /v1/jurisdictions

GET /v1/jurisdictions/NL and the MCP get_jurisdiction tool returned 404 for member states that jurisdictions= already accepts as a search filter. NL, BE, LU, MT and the 17 OAPI member states now resolve and appear in GET /v1/jurisdictions. Each has scope_type: "national", madrid_member: false and office_status: "not_covered": BOIP (BX) and OAPI (OA) are the register and the Madrid party for their members, and Signa does not connect to Malta’s register yet. See Retrieve Jurisdiction for how jurisdictions=NL and jurisdictions=BX differ on search.

October 1, 2026: opposition, proceeding status and owner corrections

Three data corrections. Records ingested from now on carry the corrected values; stored records are corrected by a backfill that follows this release. The backfill fires no watch alerts. A small number of records whose stored data we cannot fully verify may produce one update event on their next update from the office.
  • A mark in its opposition window is no longer reported as opposed. USPTO marks with status code 686 (published for opposition), EUIPO marks with APPLICATION_PUBLISHED or START_OF_OPPOSITION_PERIOD, and INPI France marks in opposition_period no longer carry opposition_pending in status.challenges. An opposition that was actually filed still does (USPTO 774 and 801, EUIPO OPPOSITION_PENDING). A USPTO request for an extension of time to oppose (802) is now other_pending. status.stage is unchanged: pending_opposition means published for opposition or opposed, and the stage alone does not tell you which. Check status.challenges.
  • Proceeding status is no longer inferred where the office did not report it. For EUIPO, CIPO and IP Australia, status is now an exact mapping of the office’s own label, still returned unchanged in status_raw.
    • EUIPO: CLOSED is other, not decided_rejected: the office reports that the case is closed but not who prevailed. Cases still running (RECEIVED, ADMISSIBILITY_CHECK, COOLING_OFF_PERIOD, and pending Board of Appeal or General Court cases) are pending. decision_date stays null for EUIPO proceedings.
    • CIPO: Active, Pending, Awaiting Decision and the appeal states are pending; Deemed Abandoned is decided_granted; Closed is other. proceeding_number is the office’s per-record sequence identifier (1, 2, …), not a Board docket number, and the API reference now says so.
    • IP Australia: Consent court order is settled, and Extension of time granted is other rather than decided_granted.
    • status.challenges follows: a CIPO or IP Australia mark whose opposition or cancellation is now pending carries the matching challenge, and one whose proceeding is no longer pending drops it.
  • A live mark no longer loses its owners. An office update that arrived without owner data used to retire the current owners of a registered or pending mark, so it was served with no owner. A live mark now keeps its current owners in that case, and marks already affected get their owners back where our stored office data shows who the current owner is.

September 30, 2026: TTAB filing dates backfilled

filed_date is now set on about 99% of US oppositions and cancellations, historical dockets included, loaded from the USPTO TTAB bulk feed. filed_date_gte, filed_date_lt, sort=filed_date and the filed_year aggregation now count those TTAB dockets. Ex parte appeals do not carry a filing date yet, and decision_date is still set on only a small share of US rows; the proceedings pages say so.

September 30, 2026: party detail ETags change once

/v1/attorneys/{id}, /v1/owners/{id}, /v1/firms/{id} and /v1/entities/{id} ETags change once. Stored attorney rows got their country_code without a change to the row, so a client revalidating a cached attorney body gets one 200 with the current country_code, then 304s again.

September 30, 2026: a trademark number in q returns that record

Searching /v1/trademarks with a trademark number in q now returns the record the number names. Before, a US designation of an international registration (a 79-series serial such as q=79412883) returned no rows, and its US registration number returned the international registration’s family row instead of the US record.
  • A number in q returns one row per record, each shown as on its detail page, with an identifier_lookup warning in search_meta.warnings.
  • A labelled international registration number, such as IR 1939139, returns one row for the international registration and its designations.
  • A bare number returns the records it names. Records whose own number is the searched number come first, such as an international registration and any national record with that number. Designations that only carry the international registration number follow.
  • A tm_ ID of a designation returns the designation, not its family.
  • Text searches are unchanged.
  • A pagination cursor issued before this change for a number in q is rejected with cursor_invalid. Start the search again.

September 30, 2026: USPTO assignments February to April 2026 complete

USPTO assignments recorded February to April 2026 are now complete (about 19,000 recordations reloaded). They are available on /v1/assignments and /v1/trademarks/{id}/assignments. The USPTO’s 6 to 10 week recordation lag still applies to the most recent two months.

September 30, 2026: USPTO attorneys of record are representative

USPTO attorneys of record now carry role: "representative" in attorneys[].role, the value every other office uses for the attorney of record. They were correspondent. Stored rows were relabelled in place. The first time we re-observe each USPTO mark after the change, that mark emits one trademark.updated webhook and watches see an attorney change; this happens once per mark. If you filter USPTO attorneys by correspondent, filter by representative instead.

September 29, 2026: firms on Madrid families

  • Grouped firm_id search matches every designation’s firm. When one attorney appears on several designations of an international registration under different firms, a grouped search filtered by firm_id now matches the family for any of those firms, not only the first, as expanded search already did. Existing families pick this up when they are next re-indexed.
  • IR detail attorney order follows designation sequence. On an international registration with several designations, attorneys[] in trademark detail is ordered by the designation’s attorney sequence, not by designation office, so it matches the search index. Multi-designation IR details may list attorneys in a new order.
  • Detail firm_name uses the firm’s display name. When the filing gives no firm name of its own, attorneys[].firm_name in trademark detail is now the firm’s display name (for example Smith & Jones, L.L.P.) instead of its upper-case matching key.

September 29, 2026: the primary image is always an image

primary_image_url and media[].is_primary now only ever point at an image file, never a document, audio or video file. A mark whose only media are office documents (for example USPTO office actions) or sound, video or 3D files has primary_image_url: null and no primary item; those files stay listed in media[]. Previously such a mark could point primary_image_url at a PDF. Trademark detail now lists the primary item first in media[]; the other items keep their order. Trademark detail applies this now; search results and portfolio rows pick it up as marks are re-indexed, and fully with the next index rebuild. has_media is unchanged.

September 29, 2026: one search request model: q, similarity, text filters and exclusions (breaking)

Search on GET and POST /v1/trademarks, the owner, attorney, firm and entity /trademarks lists, similarity watches and the MCP search_trademarks tool now share one request model. q always ranks, similarity picks the channels it runs, the mark_text_* filters decide which marks qualify, and exclusions leave marks out. The old parameters keep working until December 28, 2026. The migration guide maps each one. New parameters
  • similarity picks the channels q runs: identical, fuzzy, embedded, phonetic and lookalike. The default is identical,fuzzy,embedded,lookalike, and identical is always on. See Similarity.
  • Text filters mark_text_is, mark_text_word, mark_text_starts_with, mark_text_ends_with, mark_text_contains and mark_text_pattern test the mark text. On GET, repeat the key for several values; commas are never split. On POST, send them under filters.mark_text. Alone they list marks in text order; with q they narrow the ranked results. See Text filters.
  • Exclusions: mark_text_not_* for every text filter, plus owner_id_not, entity_id_not, entity_group_not and trademark_ids_not. On POST, send them under exclude.
  • allow_partial (options.allow_partial on POST) returns the rows found so far when a search times out, with search_meta.complete: false.
  • include=match_details adds match.details with the matching methods that fired and the ranking factors applied.
New response fields
  • match on every hit of a request with q or a text filter: { tier, via, terms }. tier is identical, near_identical, similar or related, a retrieval category rather than an edit distance. via lists the channels that found the hit. terms lists the text filter values it satisfied. See Match tiers.
  • search_meta gains similarity_applied, order (relevance, mark_text_fit, filing_date or your sort), complete, incomplete_reason, identifier, ranking_version and deprecations.
Trademark numbers in q. An application, registration or international registration number pasted into q (97134218, US 97134218, EUTM 018123456, IR 1939139, TMA911339, a tm_ ID) is looked up in addition to the text search. Its records lead the page under any sort, labelled via: ["identifier"], and search_meta.identifier shows how q was read. A bare international registration number now returns the WIPO record. See Search Trademarks. Behavior changes
  • Default recall is wider. A q without similarity now also finds marks with a different first letter, look-alike characters and prefix phrases. embedded finds the term as a word, a phrase or the start of a word in a longer mark; a term in the middle of a word is not matched yet. Abbreviation matching and owner-name matching are removed from search; use Search Owners for owner names. search_meta.ranking_version is v12.
  • Every search cursor restarts. Cursors issued before this release return 400 cursor_invalid. Cursors are now bound to the translated request, so an old-style request and its new-style equivalent share cursors.
  • Scores survive sort. With q, relevance_score and match are on every hit whatever the sort. Under a sort the score keeps the status factor and drops the length factor.
  • Text filters list in text order. Without q, a text filter orders marks equal to the value first, then marks starting with it, then shorter marks, then newer filings. The old match modes returned the newest filings first.
  • A search that times out is a 503. A search that hits its time limit or loses a shard returns a retryable 503 unless allow_partial=true. Sorted searches too; they returned 400. The partial_results warning is removed.
  • No quiet downgrades. A query too expensive to run returns 400 validation_error with errors[].code: too_complex, naming q or the text filter with the most values. It used to be retried with fewer strategies. The strategies_reduced warning is removed.
  • New limits. q takes at most 22 words. contains, ends_with and wildcard-leading pattern values need 3 characters after folding, and one request takes at most 4 of them (400 too_big). Each such value takes one slot of the search concurrency budget.
  • mark_text_not_contains ignores punctuation and spacing, like the other text filters, and takes repeated keys on GET.
  • Explicit international_registrations=grouped on a request the grouped view can’t serve returns 400 unsupported_on_grouped. Leaving it unset keeps the expanded fallback and its warning.
  • Skip warnings are per channel: <channel>_skipped with a channel field.
Watches and alerts
  • Similarity watches take version: "v3", q, similarity and min_tier (identical, near_identical, similar or related; default related). Existing watches keep alerting exactly as before until their query is changed. See Watches.
  • New watch queries use the new matching (added later on September 29). Create, bulk create, preview and an update that changes the query store it as version: "v3" whatever version you send: a plain { "version": "v2", "q": "acme" } gets the default channels and min_tier: "related". Only a query with strategies or min_match_tier is kept as a legacy watch. An update that sends the stored query back unchanged still changes nothing.
  • Alerts gain match.tier, on REST and in webhooks. match.score is still the engine score for the watch query, not the 0 to 100 relevance_score.
  • Watch preview and diagnostics report similarity_applied and min_tier.
Deprecated until December 28, 2026. strategies, match, ranking_profile, a list in q, POST query and POST top-level mark_text_not_contains are translated and listed in search_meta.deprecations. A translated request never returns fewer marks than before. On watches, strategies and min_match_tier are not translated: a watch written with them is kept as a legacy watch until it is re-saved without them, and they are listed in the response’s deprecations. From December 28, 2026, each returns 400 unknown_parameter naming its replacement. The response fields match_explanation, matched_terms, search_meta.strategies_used and search_meta.match are filled from the new data until the same date. TypeScript SDK 0.17.0 takes the new keys on trademarks.list(), trademarks.search(), the party trademarks() methods and watches, removes the old keys from the types, sends text filters as repeated keys, and exports Presets.knockout and Presets.clearance.

September 28, 2026: party counts agree, Madrid designations show their serials, USPTO address and date fixes

Fixes from a customer’s attorney-onboarding test. Nothing here removes or renames a field.
  • List and detail counts agree. GET /v1/attorneys, /v1/owners and /v1/firms list rows now read trademark_count and active_count from the same stats rows as the detail endpoints, not from the search index document. The monthly stats recompute now refreshes the search index for every party whose counts changed, and a repair pass is re-syncing attorney, firm and owner search documents (some attorneys and firms were missing from q search).
  • Party detail ETags follow the stats. /v1/attorneys/{id}, /v1/owners/{id} and /v1/firms/{id} ETags change when the stats are recomputed; /v1/entities/{id} folds its live counts in. A client revalidating a cached body gets 200 with current counts instead of 304.
  • Counting grain is in the spec. Every party stats field now says what it counts: trademark_count and active_count count marks (a Madrid IR and its designations once); registered_count, pending_count, expired_count, cancelled_count, abandoned_count, the rates and avg_prosecution_days count office records, so the status counts can sum to more than trademark_count. jurisdiction_count counts offices.
  • Madrid designations carry their own numbers. coverage.territories[] on grouped IR rows (search, party trademark lists, Retrieve Trademark, Batch Trademarks) adds the designation record’s office_code, application_number and registration_number, so a US designation shows its 79-series serial on the grouped row. Pass international_registrations=expanded for one row per designation; the party trademark list pages now document it.
  • IR detail lists its designations’ attorneys. Retrieve Trademark for a Madrid IR (grain: mark) now rolls up attorneys[] from its designations, as it already did for owners and classifications. Each attorney on such a row carries territory_codes, the designations whose record names them. IR-parent ETags change once.
  • Attorneys show their office. Attorney list and detail rows carry source_office_code. Attorney records are per office: the same person appears once per office they file at.
  • firm_id matches the firm of record. The firm_id filter and facet on trademark lists match the firm of record on the filing when known, else the attorney’s current firm, the same firm detail rows show. Index documents built before this change pick it up on the next index rebuild. USPTO filings stored before April 2026 are getting their firm of record from the correspondence address line.
  • USPTO addresses. USPTO attorney addresses are parsed into lines, city, region, postal_code and country_code (a trailing “United States” line no longer lands in lines), and USPTO attorneys get country_code: "US", so GET /v1/attorneys?country_code=US returns them. Rows whose office gave no country stay null and are excluded from a country_code filter. USPTO owners now carry their street lines in address.lines. New and updated marks get these from this release; stored rows are repaired in place without webhooks or alerts.
  • TTAB filing dates. US proceedings now take filed_date from the USPTO TTAB feed; before, only about 2% had one, so filed_date_* filters, sort=filed_date and filed_year undercounted. Historical rows are being backfilled; until the warning on the proceedings pages is removed, do not rely on TTAB date filters.
  • Assignments. The assignment pages state their scope: USPTO only, refreshed daily, with the USPTO’s 6 to 10 week recordation lag. Assignments recorded February to April 2026 are being reloaded.
  • USPTO event codes in the catalogue. GET /v1/event-types?office_code=US lists about 1,000 USPTO prosecution history codes with the event_type each maps to. SUNA (notice of acceptance of a statement of use) is now always approval; the mailed form was typed response_filed.
  • Clearer office_code error. office_code on GET /v1/trademarks still returns 400; the message now names offices (one or more codes) and office (one code).
  • Docs. Per-tier include values (full_goods_services on lists, office_extensions on detail and batch), webhook examples on payload_version: 2 with real status values, a portfolios walkthrough for status-change notifications, current plan limits, and ETag/If-None-Match change detection on List Deadline Rules.

September 28, 2026: OpenAPI nullability checked against live responses

No request or response changes. The September 27 nullability fix is now enforced by a test that validates real API responses against the published OpenAPI document, so a field the API returns as null cannot again be published as non-nullable. A nullable field that references a shared schema is declared as anyOf: [{$ref}, {type: "null"}].

September 28, 2026: one primary media item; document fields on media

  • media[].is_primary marks exactly one item whenever primary_image_url is set: the item that URL points at. A detail with several images and no office-flagged primary used to show every item as is_primary: false while primary_image_url still pointed at one of them; the two now come from one rule. When primary_image_url is null, no item is primary.
  • media[].document_kind, media[].official_date, media[].page_count are added (additive, nullable) for a document item: document_kind is the same kind GET /v1/trademarks/{id}/documents serves for that document (Signa’s classification of the office’s document type), and official_date and page_count are the office’s document date and page count, null when the office published none. All three are null for images. TypeScript SDK types regenerated.

September 28, 2026: Madrid family status.challenges is the union across designations

On an international registration whose designations disagree, status.challenges used to read ["mixed"]. It now lists the real challenges: the de-duplicated union across the designations, in a fixed order (for example ["opposition_pending"] when one designation is opposed), and [] when no designation is challenged. status.primary and status.stage still read mixed on such a family; mixed is never a challenge value. The same value appears on the trademark detail, search hits, portfolio rows and watch previews. No request or response field is added or removed.

September 28, 2026: Entity trademarks list scopes like the entity_id filter

GET /v1/entities/{id}/trademarks now returns every mark whose owner is linked to the entity, read from the same resolved entity ids as the entity_id filter on GET /v1/trademarks. The two return the same set for the same entity.
  • No member-owner cap. The endpoint no longer answers 422 entity_too_large with reason: member_owners_too_large for an entity with more than 10,000 member owners; it lists. The only remaining 422 is family_graph_too_large from include_family=true.
  • Resource semantics are unchanged. A missing entity is still 404, a merged one 410, and include_family=true still walks the entity’s own subtree. The MCP tool get_entity_trademarks follows the same scope.

September 28, 2026: filter-only order on expanded rows, mixed on the record grain

  • Filter-only requests served one row per record are newest first. A request without q or sort that is answered with expanded rows (international_registrations=expanded, or a grouped fallback such as aggregations or an unsupported sort) now returns the newest filings first (-filing_date), as documented and as the grouped view already did. Cursors minted by such requests before this release may no longer continue; start the walk again.
  • status_primary=mixed and status_stage=mixed are grouped-view filters. A request served one row per record that carries them is now a 400 validation_error (unsupported_on_record_grain, naming what forced the record grain) instead of an empty page.
  • debug_timing is no longer documented on GET /v1/trademarks. It never changed a response; it is still accepted and ignored.
  • TypeScript SDK 0.16.0 drops ranking_profile and options.include_profile from the search types.

September 28, 2026: q takes a list of exact terms; q_any is replaced (breaking)

Search has one text field again. q on GET and POST /v1/trademarks takes either one term, as before, or a list of exact terms. q_any is replaced by the list form.
  • The list form. On GET, write the whole value as a JSON array of strings: q=["limber","bimber"]. On POST, send an array in query or q: {"query": ["limber", "bimber"]}. The response is the same as q_any gave: every mark that is an exact match for any term, each hit carrying matched_terms, and search_meta.match reads exact. See Several exact terms.
  • One term is unchanged. A string q works exactly as before. It is always literal text: no operators, no comma splitting. Only a value that parses in full as a JSON array of strings is a list, so [RE]BUILD and [1,2] are still searched as written.
  • A list runs match=exact. It is the default for a list, and sending it is allowed. Any other match, or strategies, with a list is a 400 validation_error.
  • 100 terms per list (q_any took 200), each up to 200 characters. Long lists go by POST: a GET query string over 2 KB is rejected before it reaches the API.
  • q_any is replaced. A request that sends q_any gets a 400 validation_error whose message names the list form; move the terms into q unchanged. The request is not billed and never runs as a filter-only search. Cursors minted by q_any requests may no longer continue; start the walk again.
  • Pricing is unchanged. One page of a list search costs the same as one page of any search, regardless of how many terms it carries.
  • TypeScript SDK 0.15.0 types q as string | string[] on trademarks.list() and trademarks.search() and removes q_any. SDK 0.14.0 sends q_any, so upgrade before relying on the list form.

September 28, 2026: mixed_script search warning

match=exact, starts_with, ends_with, contains and q_any compare letters as written, so a look-alike spelling such as τιmbεr (Greek letters among Latin ones) finds only marks spelled with those exact characters. When a term mixes Latin with Greek or Cyrillic letters, search_meta.warnings now includes mixed_script (severity: info, affected_filter: q or q_any) naming the spelling. Results are unchanged. Ranked search with strategies=exact folds look-alike letters and carries no warning.

September 27, 2026: Provenance release follow-ups

  • CIPO status labels. Signa used to join CIPO’s status and its internal description into one status.raw.label (for example Registration published - Registered). The label is now CIPO’s internal description alone (Registered), the same text a record without a status code carries. status.raw.code is unchanged, and List Status Codes still serves null labels for CIPO.
  • EUIPO event labels. On EUIPO trademark events whose text Signa composed from several fields (bulletin publications, oppositions, cancellations, appeals, seniorities, decisions), raw is null and the text stays in description. EUIPO’s own recordal kinds, such as Proprietor - Total transfers, are still served as raw.label.
  • IPOS event labels. The filing and registration events Signa adds to IPOS trademarks (Application filed, Registration procedure completed) use Signa’s wording, so raw is null and the text stays in description. IPOS’s own event entries are unchanged.
  • INPI event codes. Signa used to join INPI fields into one event code, such as Inscription: Changement d'adresse or Transaction: Correction. raw now carries the fields alone: a recordal is {"code": "Inscription", "label": "Changement d'adresse"} and a weekly transaction is {"code": null, "label": "Correction"}. Events from INPI’s status history are unchanged.
  • OpenAPI nullability. Enums documented as nullable now list null among their values, and derived.next_deadline is declared as a DeadlineRow or null. Responses are unchanged; a strict OpenAPI validator now accepts the null values the API already returned.
  • Event types. List Event Types catalogues IP Australia (AU) and WIPO (WO) codes today. Other offices return an empty list.

September 27, 2026: The provenance release (breaking)

This is one breaking release, announced ahead of time to beta accounts. After it, every value says whether the office published it or Signa computed it, in one vocabulary, and a search hit is the same row as the detail. Update your integration and the TypeScript SDK (0.14.0) together. The headline: top-level dates are the office’s own. expiry_date and renewal_due_date are null when the office published none. The USPTO publishes no expiry date, so expiry_date is null on every USPTO record; the rulebook’s term end is derived.expiry_date. Filters and sorts on expiry_date and renewal_due_date follow the office values too.

Trademark rows (search, lists, portfolios, screening, batch, detail)

  • Status. status.source is now status.basis (office, event_derived, dispatch_derived, computed). status.raw_code and status.raw_label are now status.raw: {code, label} (or null). The label is the office’s verbatim text only: null when the office publishes none, or when the stored text was the code itself or wording Signa wrote. Decode codes with the new List Status Codes.
  • Dates. expiry_date_basis and renewal_due_date_basis are removed; top-level dates are office-published only. New last_renewal_date, the last renewal the office recorded (USPTO, CIPO and OEPM today). In every jurisdiction the rulebook treats the renewal cycle it paid, and every earlier cycle, as paid, so an early-renewed registration no longer lists the paid cycle as due. last_renewal_date on a POST /v1/deadlines/compute item works the same way (it used to be read for Canada only). A paid cycle is not a missed one either: urgency=missed on GET /v1/deadlines and portfolio deadlines, and include_missed: true on POST /v1/deadlines/compute, no longer list a cycle before the office-stated expiry, the cycle a recorded renewal paid, or the restoration window such a cycle would open. include_missed used to return that paid history.
  • An IR’s expiry_date is the expiry WIPO published on its designations. Known limitation: the search index does not hold it on the IR’s own record yet, so expiry_date_* does not match the IR’s own record and sort=expiry_date orders it with rows that have no office expiry. The next index rebuild fixes this. Also known: a renewal WIPO publishes on the designations moves the IR’s expiry_date without raising a trademark.updated event or alert for the IR’s own id (Watches).
  • derived on every row, search hits included: ruleset_version (an rs_ content hash, was a date), as_of_date, expiry_date, deadlines {supported, reason, unsupported_rules, items[]}, next_deadline and opposition_window. The detail’s deadlines_supported, deadlines_unsupported_reason and deadlines_unsupported_rules move into derived.deadlines, and the deadline array into derived.deadlines.items.
  • Opposition window. The top-level opposition_window on search rows is removed. derived.opposition_window is always present and two-state: {supported: true, rule_id, trigger_event, publication_date, window_opens, window_closes, close_adjustment, office_time_zone, common_extension} or {supported: false, reason, rule_id} with no null date keys. rule_version is removed.
  • Deadline rows, everywhere a deadline appears (the derived block, GET /v1/deadlines, portfolio deadlines, POST /v1/deadlines/compute): grace_expiry is grace_expiry_date, recurring and optional are is_recurring and is_optional, name and description are removed, and new occurrence_key, due_date_adjustment, grace_expiry_adjustment, holiday_calendar and consequence_if_missed appear on every row. occurrence_key identifies one occurrence within one trademark across reads: rule_id:<cycle>, or rule_id:t<term>-<n> when the record has no statutory anchor date or the row is anchored on an office-stated expiry. The calendar event UID namespaces it by trademark: tm_<uuid>:<occurrence_key>@signa.so. Madrid rules report jurisdiction_code: "WO", and a POST /v1/deadlines/compute item sent as WIPO echoes WO.
  • Office record. source_primary_id is replaced by office_record_id (the office’s own id; null only when Signa composed the key: an IR’s own record and its WIPO-feed, Finnish and Polish designation records; other national-office records of a designation keep the office’s id) and office_url.
  • IR numbers lose Signa’s WO prefix in registration_number ("WO921642" is now "921642"), and the registration_number filter matches the unprefixed number.
  • Owners. owners[].entity_id is the resolved entity or null; owners[].entity_id_type is removed; owners[].entity_type is now owners[].legal_form. Detail owners gain is_current.
  • Attorneys (detail): attorneys[].firm_id and firm_name are the firm of record on the filing, falling back to the attorney’s current firm (they used to be the current firm). The firm_id filter and facet still match the attorney’s current firm, so about 5% of records can be returned for a different firm than their detail shows, until the next index rebuild.
  • Addresses have one shape everywhere (owners, attorneys, assignment parties): {lines[], city, region, postal_code, country_code, formatted}. state is region, lines are verbatim, and components appear only when the office supplied them.
  • Register. The detail’s us_register is replaced by register {type, acquired_distinctiveness, is_incontestable, standard_characters_claimed} (or null), on every row and for every office that states one.
  • Grain. New grain: "mark" | "record". coverage, source_records and owners_mixed appear only on Madrid IR family rows (they were null on others). Coverage territories are {territory_code, status {primary, stage}, trademark {id, href}, office_url, ...} (they were territory, primary, stage and trademark_id), and the IR’s own WO record is no longer listed as a territory.
  • The row-level office_updated_at is removed (the detail keeps it under provenance, which gains snapshot_date).
  • territory_matches[].basis is matched_via_kind.
  • classifications[].class_status_raw is classifications[].status_raw {code, label}.
  • design_codes[] are {system, code, edition} (were code_system, code_value), with system one of vienna, us_design_search, other.
  • filing_bases[].nice_class_number is filing_bases[].nice_class.
  • classifications[].scope (as_filed) appears only on IR family rows.
  • classifications[].nice_class can be null (a class the office stated without a Nice number).
  • The detail’s jurisdiction_code can be null, as on the row.

Search and filters

  • Removed filters (now a 400): renewal_due_before (use renewal_due_date_lt), us_register_type (use register_type, which works for any office register), opposition_closes_before and opposition_closes_after (use opposition_closes_lte and opposition_closes_gte). This applies to GET and POST /v1/trademarks and to the owner, attorney, firm and entity trademark lists.
  • Grouped per-leg filters. On the default grouped view, the office, route, filing, registration and expiry date and registration number filters stay grouped, alone or together: they must hold on the same record, and they match the leg shown in coverage.territories[] for each territory. When a territory has both a WIPO-feed and a national-feed record, the one Signa does not show (listed in source_records) does not match.
  • search_meta.fallback_reason is removed. A grouped request served one row per record now carries an expanded_fallback entry in search_meta.warnings[] with affected_filters or affected_option.
  • search_meta.index_generation is new. Cursors are bound to the index generation, so a cursor minted before this release is rejected with 400 cursor_invalid: restart pagination. The same applies after any future index rebuild.
  • New result_window_reached warning (severity: info) in search_meta.warnings[]: the last page of a relevance-ranked or sorted walk that the 10,000-row window ended while more rows match. A walk that ran out of matches never carries it.
  • entity_id and entity_group with an owner id in entity form (ent_<owner-uuid>) return an empty page. Filter a single owner with owner_id.
  • entity_id and entity_group on trademark search no longer return 422 entity_too_large for an entity with more than 10,000 member owners; they match the entity directly. entity_group keeps its family-walk bound, and the other entity surfaces keep the member cap (errors).
  • opposition_status and opposition_closes_* match only while the mark is at a stage it can be opposed at (the gate behind stage_not_opposable); they used to match at any stage.
  • If Signa cannot load a result page’s stored data (owner entity links, record facts, IR family facts), a trademark search or list request now fails with a retryable 503 service_unavailable and Retry-After: 5 instead of serving a degraded page. An owner-lookup failure used to serve owners[].entity_id: null and show owners that are normally hidden.

Other endpoints

  • Batch (POST /v1/trademarks/batch): identifiers name their office with office_code (office is now a 400). data answers every submitted item in input order, and a repeated id repeats.
  • Events (GET /v1/trademarks/{id}/events): rows are object: "trademark_event" with their own hst_ ids (were event and evt_); raw_code and raw_label are raw {code, label}; nice_class_number is nice_class; sequence_no is sequence_number; description is null unless it adds office text to raw.label. The org feed GET /v1/events keeps object: "event".
  • USPTO event types. A USPTO notice of suit (NOSU) is event_type: "litigation" (was office_action), so it no longer matches event_type=office_action and no longer raises office_action.issued. Attorney and domestic-representative appointments, revocations and withdrawals are representative_changed (were address_change); a representative’s own address change stays address_change. Labels naming the USPTO’s examining attorney, which the old rule also filed as address_change, take the type their label maps to (for example other or correction). Stored history is retyped after the release, with no webhook or alert.
  • Entities. entity_id_type is removed. Entities are materialized entities only: GET /v1/entities/{id} (and /trademarks, /family) with an owner id in entity form is a 404, linked owner or not; a merged entity stays 410. GET /v1/entities no longer lists unlinked owners, and members[].link is never null.
  • Owners, attorneys, firms. Owner entity_id (list and detail) is the linked entity or null, and entity_id_type is removed. Stats earliest_filing and latest_filing are earliest_filing_date and latest_filing_date (sort values are unchanged). aliases[].source_office is source_office_code. address is the one address shape.
  • legal_form on every party. entity_type is legal_form on owners (list and detail), attorney clients (GET /v1/attorneys/{id}/clients), entities (list and detail) and entity members[], as on trademark owners[]. The GET /v1/owners and GET /v1/entities filter entity_type is legal_form (the old name is a 400 that names it).
  • Proceedings (GET /v1/proceedings/{id}): trademark.serial_number and trademarks[].serial_number are application_number.
  • Event types (GET /v1/event-types): raw_code and raw_label are raw {code, label}, as on a trademark event. The label follows the verbatim-label rule, so WIPO rows (whose catalogue labels are Signa’s descriptions) have label: null. The office filter is office_code, as on GET /v1/status-codes; office and any other unknown parameter are a 400.
  • Assignments. reel_no, frame_no, release_of_reel_no and release_of_frame_no end in _number; new office_code. Parties: nationality is country_code (ISO alpha-2, null when the office named no country) and address is the one address shape. Properties: serial_no, registration_no, intl_reg_no and mark_name are application_number, registration_number, ir_number and mark_text.
  • Deadlines. unsupported_marks[].unsupported_reason is reason on GET /v1/deadlines and portfolio deadlines. Compute items: unsupported_reason is reason. Opposition compute items fold unsupported_reason into reason. Reconcile computed.unsupported_reason is computed.reason. GET /v1/deadline-rules reports Madrid rules as jurisdiction_code: "WO" (was WIPO); its jurisdiction filter still accepts WIPO as an alias.
  • Calendar (GET /v1/portfolios/{id}/deadlines.ics): event UIDs are tm_<id>:<occurrence_key>@signa.so. A file downloaded after the release adds every event again beside the ones imported earlier (delete those once); afterwards, re-importing updates an event whose due date was corrected instead of duplicating it.
  • Offices (GET /v1/offices, /v1/offices/{code}): coverage and coverage_computed_at are data_completeness and data_completeness_computed_at. data_completeness.expiry_date counts office-stated expiries only.
  • Citations: disposition_as_of is disposition_at.
  • Goods and services suggest: accepted_terms[].harmonised is is_harmonised.
  • Office analytics: earliest_filing and latest_filing are earliest_filing_date and latest_filing_date.
  • Screening: screening_id values change once (the receipt now binds the served index generation) and again after each index rebuild.
  • ETags change format. Every cached validator gets one 200, then 304s resume.
  • Watches: a watch filtering on expiryDate or renewalDueDate now matches office-published values, like the search filters. New watches cannot target an owner id in entity form; use filters.ownerId. Existing watches that did are migrated to filters.ownerId, or to the entity the owner has since been linked into, and keep evaluating the same marks.
  • New: List Status Codes (GET /v1/status-codes?office_code=US; unknown query parameters are a 400).

Webhooks and GET /v1/events (payload_version 2)

New events are payload_version: 2 from September 27, 2026. Every event keeps the version it was stored with: automatic retries, /redeliver and GET /v1/events/{id} of an event recorded before then stay v1, so handle both for the 30-day replay window. See Webhooks.
  • office_action.issued v2 replaces the flat event_date, event_code, event_label, scope, status_after_event, nice_class_number, description, source_identifier and sequence_no with trademark_event, the same row GET /v1/trademarks/{id}/events returns.
  • Change field names in v2 (trademark.status_changed changed_fields and changes, alert.created alert.event.diff[].path, and REST alert event.diff[].path): source_primary_id is office_record_id, status_source is status_basis, and expiry_date_basis and renewal_due_date_basis are no longer published.
  • Change values in v2 follow the row: status_basis uses the status.basis vocabulary; an expiry_date or renewal_due_date side that is not office-stated is null, and a change between two computed values is omitted; status_raw_label follows the verbatim-label rule; registration_number has no WO prefix.
  • No alert is raised for a change whose every changed field is one the row does not publish (a Signa-computed date moving, or a basis change that stays non-office), so an alert never arrives with an empty diff.
  • Both versions: on events emitted from the release on, data.occurred_at is ISO 8601 UTC with milliseconds (2026-09-26T22:23:21.191Z), as GET /v1/events serves it. It used to carry Postgres text (2026-09-26 22:23:21.191924+00), which strict ISO parsers rejected. Retries and redeliveries of events emitted before the release keep the old text.

MCP

get_trademark_events returns the trademark_event rows; get_entity, get_entity_trademarks and get_entity_family treat an owner id in entity form as not found; batch_get_trademarks answers in input order; search_trademarks and the party trademark tools take register_type, opposition_status and opposition_closes_gte/_lte; list_offices and get_office carry data_completeness; get_trademark, get_trademark_events and the new list_status_codes declare an output schema. list_event_types returns raw {code, label} rows, pages with the REST cursor and takes office_code (was office). list_owners and list_entities take legal_form (was entity_type). get_deadline_rules reports Madrid rules as jurisdiction_code: "WO" (was WIPO). Every tool rejects an argument it does not declare (a retired filter name or a typo) with an input validation error instead of ignoring it. A tool result that fails its declared output schema is an unbilled tool error (it used to be charged, then rejected by the client). A tool that fails with an API error (for example not found or a validation error) returns the typed JSON error body REST returns ({"error": {"type", "status", "title", "detail", ...}}, including errors[].code) instead of a Failed to get X: ... message.

Upgrading

  1. Read expiry as expiry_date ?? derived.expiry_date, and deadlines from derived.deadlines.items.
  2. Rename the filters above, and batch office to office_code.
  3. Treat owners[].entity_id as nullable, and use owner_id for unlinked owners.
  4. Restart any paginated walk that spans the release.
  5. Branch webhook handlers on payload_version.
  6. Upgrade to @signa-so/sdk 0.14.0 (TypeScript SDK). Its types follow every change above. The old filter names are not translated: the API answers them with a 400 naming the replacement, and list()’s POST fallback throws a SignaError that names it. toArray() never returns a short array silently: it throws SignaTruncatedError past its 10,000-item default cap, and also when the API ended a relevance-ranked or sorted search at its 10,000-row window while more rows match (the last page’s result_window_reached warning).

September 24, 2026: Declined deadline rules and uncomputed marks are now listed

When a deadline rule applies to a mark but the record lacks the date the law runs it from, Signa declines to guess and computes no row for it. Until now that rule simply did not appear. Three surfaces now name it. All changes are additive.
  • POST /v1/deadlines/compute: every item carries unsupported_rules, an array of { rule_id, reason, missing_field, consequence_if_missed }. It is [] when nothing was declined, and [] when supported is false, because unsupported_reason already covers every rule.
  • GET /v1/trademarks/{id}, POST /v1/trademarks/batch and the MCP get_trademark tool: the derived block carries deadlines_unsupported_rules in the same shape, next to deadlines_supported and deadlines_unsupported_reason.
  • GET /v1/deadlines and GET /v1/portfolios/{id}/deadlines: the list envelope carries unsupported_marks, one entry per mark in the requested portfolio or trademark that was not computed at all (supported: false) or was computed only in part (supported: true with unsupported_rules). Marks with a status that ends every obligation, such as abandoned or withdrawn, are not listed. Entries use the same supported, unsupported_reason and unsupported_rules fields as a compute item. The list covers the whole scope, not just the page, ignores the type, urgency and due_before filters, and is sorted by trademark_id. It is reported on the first page (a request without cursor) and is null on continuation pages.
A rule is declined when the date it runs from is owed but absent: a filing date, an international registration date, or, once the mark is registered, its registration or grant date. A registration-anchored rule on an application not yet registered is not declined, because nothing is due yet. The Philippine fifth-year declaration of use for a Madrid designation (ph_declaration_of_use_5yr_madrid) runs from the statement of grant of protection (IPOPHL MC 17-011 Rule 20(2)); send protection_grant_date on a compute item and the row is computed. When every rule a mark owes is declined this way, the whole mark declines with supported: false and unsupported_reason: "requires_office_date", for example a Swedish mark registered on or after 2019-01-01 with no filing date, or a registered US mark with no registration date. Such a mark was previously reported as supported with no deadlines. Whole-mark declines in unsupported_marks also cover the existing unsupported_reason cohorts, such as Australian direct marks filed before 1996, Singapore direct marks filed before 15 January 1999, Madrid designations without an international registration date, and jurisdictions Signa does not model. The portfolio calendar download (deadlines.ics) cannot carry this list, since a calendar file holds only dated events. Read unsupported_marks from the JSON list to see which marks and rules are missing from it.

September 24, 2026: Older Nordic registrations without a filing date get deadlines

Swedish, Icelandic, Norwegian and Finnish direct (non-Madrid) records with no filing date and a registration date before the office’s renewal-anchor change (SE 2019-01-01, IS 2020-09-01, NO 2010-07-01, FI 2019-05-01) got no maintenance deadlines. They now compute from the registration date, which the transitional provisions key on for marks registered before the change (SE SFS 2018:1652 p. 4 a; IS L. 71/2020 39. gr. 3. mgr.; FI 544/2019 107 § 4 mom.; NO Varemerkeloven § 83 with § 22). A record registered on or after the change date with no filing date now declines with unsupported_reason: "requires_office_date", since its term runs from the filing date it lacks. GET /v1/deadline-rules publishes the rule as trigger_before_proves_cohort, true on the SE, NO, FI and IS rules. See Nordic countries.

September 24, 2026: Monitoring and reconcile on every plan; internal actions leave Get Credit Pricing

Mark watch, Filing watch (similarity, owner and class watches) and marks under management are available on every plan, Free included, and cost no credits during the beta. Creating a similarity, owner or class watch on Free no longer returns 403 plan_gated. The watch, portfolio and managed-mark count limits for each plan are unchanged. Reconcile is available on Free as well. POST /v1/reconcile no longer returns 403 plan_gated on a Free key. It still costs 1 credit per record, spent from your monthly pool. Get Credit Pricing no longer lists internal-only actions (screening, compare and listing check) for any key, and status is now one of available, beta or planned. They were never available to self-serve keys and have no published price yet. SDK users: CreditPrice.status no longer includes 'internal', so code that compares against it or switches exhaustively on status needs updating.

September 24, 2026: offices and filing_route keep Madrid results grouped

An offices or filing_route filter switched a default (grouped) search to one row per Madrid designation: offices=WO returned several rows per IR, no coverage, and a total_count that counted designations. Once the rebuilt search index is live, offices, office and filing_route stay grouped when they are the request’s only filters. An IR then appears once, with its coverage, when its WIPO record or any record linked to it matches. Combined with another filter (status_primary, jurisdictions, nice_classes, …) they still fall back to expanded, because the grouped row cannot tell whether both conditions hold on the same designation; search_meta.fallback_reason names the pair, for example filter:offices+status_primary forced expanded. owner_name stays grouped from the same point. The per-designation date filters (filing_date_*, registration_date_*, expiry_date_*) still fall back. offices matches the office a record comes from. offices=CA returns CIPO records, not the WIPO records of IRs designating Canada. To find every IR designating Canada, use jurisdictions=CA, which stays grouped. The search reference described the fallback the wrong way round. A grouped request the grouped view can’t serve falls back to expanded, never the reverse.

September 24, 2026: Canadian and Brazilian date rolls, six-month Madrid renewal windows, and new deadline fields

Some maintenance dates move. Maintenance deadlines are recomputed on every request (POST /v1/deadlines/compute, the trademark derived block, GET /v1/deadlines), so these apply now, with no reindex.
  • Canada: grace_expiry rolls to the next day the office is open (Trademarks Act s. 66(1)), reported in grace_expiry_adjustment. due_date never rolls: it is the end of the term. window_opens on the office-anchored ladder no longer falls before the registration date (Regulations s. 159(a)).
  • Brazil: due_date and grace_expiry roll to the next business day (Lei 9.784/99 art. 66 § 1º, applied by art. 69), reported in due_date_adjustment and grace_expiry_adjustment.
  • Madrid designations in CH, FR, AU, FI, PL, BR, IN, KR and CN: the renewal window_opens is six months before the due date, the period the International Bureau accepts a renewal in (Common Regulations Rule 30(1)(b)). It was 12 months. due_date and grace_expiry do not change.
  • India: the 7-year or 10-year first term is chosen by the Indian filing date, not the convention priority date. A convention application filed on or after 15 September 2003 with an earlier priority date now gets the 10-year term (filed 1 October 2003, priority 1 May 2003: due 1 May 2013, was 1 May 2010). The priority date is still the date the term is counted from.
GET /v1/deadline-rules reflects the Canadian and Brazilian rolls: ca_renewal has holiday_calendar: "cipo_canada", weekend_holiday_rule: true and grace_expiry_rolls_only: true; br_renewal has holiday_calendar: "br_brazil" and weekend_holiday_rule: true. Alerts say whether their deadline was checked against a holiday calendar. An alert’s must_act_by is fixed when the alert is created. The new deadline.must_act_by_adjustment (moved, unchanged, not_checked or month_end_overflow) travels with it on GET /v1/alerts, the alert detail, the signed webhook body and the MCP alert tools. not_checked means no office calendar was consulted, so the date may be early but never late: act on it, but confirm it before you record it as final. The field is null on alerts created before this release and on alerts with no opposition window; null means no marker was recorded, not that the date was verified. Watch diagnostics publish both opposition close dates. The opposition block of GET /v1/watches/{id}/diagnostics now carries recomputed_close, the close computed at request time, next to must_act_by, the alert’s fixed date. The two can differ, for example after an office publishes a closure notice. close_adjustment now always describes the date in must_act_by. GET /v1/opposition-rules gains three fields. window_change_comparison_field (publication_date, filing_date or null) names the date compared against window_change_date; tr_opposition compares the filing date. extension_change_date and common_extension_before give the common extension that applied before a change, which the catalog did not publish: CIPO went from 4 months to 2 on 2023-12-01, and IPOPHL from three 30-day extensions to one 45-day extension on 2022-06-30. POST /v1/oppositions/compute already used the earlier figure for an earlier close. office_code on GET /v1/opposition-rules is filled in for every office. It was null for offices Signa has rules for but no register from (JP, IN, TR, KR, CN, BX, DK, FI, PL, TH, VN, PH, IS), so joining it to POST /v1/oppositions/compute found nothing for them. ?office= now accepts those codes; it returned 400 before.

September 24, 2026: q_any checks up to 200 exact terms in one request

GET and POST /v1/trademarks accept q_any: a list of up to 200 terms, each at most 200 characters. It returns every mark that is an exact match for any term, under the same rules as match=exact (case, accents, punctuation and spacing), and each hit carries matched_terms, the terms it matched as you spelled them. A clearance check over every one-letter variant of a word becomes one request instead of hundreds. One page costs the same as any search page. Mind the request size: the API rejects a GET query string over 2 KB (403) and a POST body over 8 KB (413) before your request reaches it. Send more than a few short terms with POST, and split very large batches. The TypeScript SDK keeps 700 bytes free for the page cursor: trademarks.list() runs the walk by POST once the GET query string passes about 1.3 KB, and trademarks.search() refuses a body over about 7.3 KB. See Several exact terms.

September 24, 2026: One-character searches on owner, attorney and firm trademark lists

GET /v1/owners/{id}/trademarks, /v1/attorneys/{id}/trademarks, /v1/firms/{id}/trademarks and /v1/entities/{id}/trademarks accepted a one-character q but always returned an empty page. They now return that party’s marks whose whole text is that character (ignoring case, accents and punctuation), and search_meta.warnings lists the strategies that cannot run on one character (for example fuzzy_skipped). GET /v1/trademarks still requires at least two characters for match=similar, except a single Chinese, Japanese or Korean character.

September 24, 2026: Watches accept one- and two-character CJK keywords

A watch or watch preview whose q contained a Chinese, Japanese or Korean word of one or two characters (愛, 東京) was rejected with 400 validation_error (“Keyword too short”), although search accepts it. Such words now pass; the 3-character minimum still applies to every other keyword.

September 24, 2026: Mixed-alphabet and accented queries match like the index

Exact matching and the normalized search lanes folded some queries differently from the index, so they missed marks or matched the wrong ones. A mixed-script query such as τιmbεr was reduced to mbr and returned MBR marks, and MÜLLER lost its Ü and missed MÜLLER. Greek and Cyrillic accents (άλφα, Й) were stripped although the index keeps them, and full-width characters (A) were not folded. Queries now fold exactly as the index does, so these match the marks you would expect.

September 24, 2026: Screening and compare no longer reject brackets and parentheses

GET /v1/screening rejected any q containing [ ] ( ) { } | \ or a regex pattern such as .* with 400 validation_error, and so did GET /v1/screening?trademark_id=… whenever the register mark itself contained them, which no caller could work around. Screening and /v1/compare now remove these characters before the search runs, the same way trademark search does. The identical registered mark is still found under sensitivity=strict: the exact-match check compares the text as sent. A screening q or a compare mark with nothing left afterwards still returns 400; a trademark whose mark text has nothing searchable returns 422 not_screenable. Listing checks are unchanged.

September 23, 2026: Long name searches return 400, not 503

A search query that is too long to run now fails fast with a 400 you can fix, instead of a 503 that invited retries. A long q, such as a full legal line pasted from a filing, could exceed the search engine’s limit on how many clauses one query may contain. We answered that with a retryable 503, so clients retried a request that could never succeed. On very long name searches for entities, owners, attorneys, and firms, typo-tolerant matching now uses only the leading terms of q. Exact whole-name matching still uses the full text. If a query still exceeds the search engine’s limit, the API returns 400 validation_error with retryable: false instead of a retryable 503. When the request has a q, the errors[] array names it: { "field": "q", "code": "too_complex" }. Shorten q and send it again. A 503 now means only that search is temporarily unavailable. Trademark search first retries once with the cheap strategies you requested (exact, prefix) and reports that in search_meta.strategies_used; if you requested neither, or used a match mode or q_any, it returns the same 400.

September 23, 2026: Abandoned searches stop, and partial pages say so

When a client disconnects from GET or POST /v1/trademarks or POST /v1/watches/preview, the search it started is now cancelled instead of running to completion. Other endpoints (owners, attorneys, firms, entities, suggest, screening, image search) are not covered yet. Searches on the request path no longer retry a timed-out query at the transport level, and a trademark search stops within about 20 seconds with a retryable 503 rather than stacking retries. A page whose search hit its time limit or lost a shard now carries a partial_results entry in search_meta.warnings.

September 23, 2026: Relevance search pages to 10,000 rows on both views

A relevance search (q, no sort) now pages to 10,000 rows on both the default grouped view and the expanded per-designation view. The expanded view (used for international_registrations=expanded, aggregations, or a filter the grouped view does not support) used to stop after 400 rows with 400 cursor_window_exceeded. The grouped view used to switch to a different ordering after row 400, so a long walk could repeat or skip marks. Now every page on either view runs the same query, the walk has no gaps or repeats, and the last page inside 10,000 is served in full or in part and ends with has_more: false. Restart long grouped walks. A grouped relevance cursor minted before this release for a page past row 400 now fails with 400 cursor_window_exceeded, and its detail says the cursor is from an older release: restart from the first page. Cursors for the first 400 rows, and expanded-view cursors, keep working. See Pagination windows.

September 23, 2026: entity_count and owner_count aggregations

Trademark search accepts two new count aggregations, each returning { "value": n } for the result set. entity_count counts distinct parties across offices (resolved entities; an owner not resolved to an entity yet counts once per office record) and is the one to use for “how many owners hold this phrase”. owner_count counts distinct owner records, which are per office, so one company filing in four offices counts four times. The owner_id aggregation lists only the top 50 owners, so it could not answer either question. Both counts are close to exact up to 40,000 and approximate above that.

September 23, 2026: match=exact ignores punctuation and spacing

match=exact compared punctuation literally: LET'S GO found the marks written LET'S GO but LETS GO found nothing, and text normalized with apostrophes turned into spaces (I DON T) never matched I DON'T. Exact matching now folds case, accents, punctuation and spacing, so those spellings all find the same marks. As a consequence, KIT KAT and KITKAT are also an exact match for each other. q_any follows the same rules, so a batch of terms finds every mark the matching single-term requests would. starts_with, ends_with and contains are unchanged.

September 23, 2026: Single CJK characters are valid search queries

The default match=similar mode required q to be at least 2 characters, which rejected single-character Chinese, Japanese and Korean marks such as 愛 or 馬 with 400 validation_error. A single CJK ideograph, Hangul syllable or Kana character is now accepted and searched. Other one-character queries still need a deterministic match mode.

September 23, 2026: Brackets and parentheses in q no longer return 400

GET and POST /v1/trademarks (default match=similar) and GET /v1/trademarks/suggest used to reject any q containing [ ] ( ) { } | \ or a regex pattern such as .* with 400 validation_error. That also rejected real mark text such as EAT. SLEEP. FIGHT. (REPEAT) and DON'T SCARE ME [I POOP EASILY]. These characters are now removed before the search runs. A q with nothing left afterwards, such as .*, still returns 400. The deterministic match modes (exact, starts_with, ends_with, contains) do not remove them. Screening and compare followed on September 24 (see above); listing checks still reject these characters per candidate with a 400. Watch queries follow the same rule. A watch q with these characters is accepted and stored exactly as sent; searches ignore the characters, and an exact-tier watch still matches a mark written with them. Watches that were previously skipped because their stored q contained such characters are now evaluated and may start alerting.

September 23, 2026: Watch preview evaluates the watch query

Fixed: POST /v1/watches/preview ignored q on large scopes. When the changes in the trial window exceeded an internal cap (common for a similarity watch over US or EU), the preview returned the number of changed marks, for example 659,662, as estimated_match_count, and results held marks that did not match q. min_match_tier and trigger_events did not change the number, and some queries hit 504 preview_timeout after 10 to 15 seconds. A watch with a text query is now evaluated query first: the preview searches for q with your strategies and filters, applies min_match_tier, keeps the marks that changed in the window with a matching trigger_events type, and returns those. results are ordered by relevance. When the count cannot be exact, estimate_basis says which way it can be off: query_upper_bound (can only be too high) or lower_bound (can only be too low). For a watch with a text query, a timeout returns 200 with partial: true and the verified count instead of a 504, and an unavailable search returns a retryable 503. See Preview Watch.

September 23, 2026: strategies now runs only the strategies you pass

Fixed: strategies=exact also ran a synonym lane. A request such as q=OUTER BANKS&strategies=exact returned OUTER BANKS BIKE WEEK and HIDDEN GUARDIANS OF THE OUTER BANKS with strategies_matched: ["synonym"], while search_meta.strategies_used reported ["exact"]. Synonym matching is part of the fuzzy strategy and now runs only when fuzzy is requested (it is in the default exact,fuzzy set). Serial and registration number lookups now belong to exact. Every strategies_matched label now belongs to a strategy in strategies_used. The same applies when OpenSearch rejects a query as too expensive: the single retry runs only the cheap strategies among those you asked for (exact, prefix; exact for the default set), and search_meta.strategies_used reports what was served, and a strategies_reduced warning lists the dropped_strategies. If you asked for neither, for example strategies=phonetic, the response is 400 validation_error with { "field": "q", "code": "too_complex" } when the query was too large (shorten q or add exact/prefix; retrying does not help), or a retryable 503 service_unavailable with Retry-After when the cluster was overloaded. The default grouped view now follows the same rule; before, such a failure there was a 500. Watches are unchanged: live watches and watch previews keep the lanes they had before this change, so no stored watch starts or stops alerting.

September 23, 2026: Aggregation counts now respect your filters

Fixed: aggregations on GET and POST /v1/trademarks ignored every filter. Bucket counts were computed on q alone, so offices, nice_classes, status_primary, date ranges and the other filters narrowed the results but not the counts. A search filtered to offices=US,EM,WO still returned office_code buckets for GB, FR and CA, and the buckets could add up to several times total_count. aggregations_only=true had the same problem. Aggregations now count the same set as the results: q, the match mode and every filter. For single-valued fields such as office_code and status_stage, the buckets add up to total_count. If you cached counts from an aggregation request, refresh them. For a drill-down sidebar, pass aggregation_mode=exclude_own_filter (options.aggregation_mode on POST). This is not the old behavior, which ignored every filter. Each aggregation then applies every filter except its own, so the office_code buckets ignore offices but still respect nice_classes and status_primary. See Statistics view.

September 23, 2026: pre-reform Nordic records without a registration date are declined

Swedish, Icelandic, Norwegian and Finnish direct (non-Madrid) records filed before the office’s renewal-anchor change date (SE 2019-01-01, IS 2020-09-01, NO 2010-07-01, FI 2019-05-01) that carry no registration date now decline with supported: false and unsupported_reason: "requires_office_date", unless the mark is finally dead. Previously SE and IS served a filing-anchored renewal date, which could be years late after its first cycle, and NO and FI returned an empty schedule reported as supported. Madrid designations are unaffected (they renew on the international registration date), and an office-stated expiry_date, or a renewal_due_date with basis reported, still anchors and computes the schedule. See Nordic countries.

September 23, 2026: close_adjustment gains month_end_overflow

opposition_window.close_adjustment can now be month_end_overflow. It was moved, unchanged or not_checked; there is a fourth value, and it appears only on Mexican windows. Reglamento LPI art. 4o, párrafo segundo sends a period whose day number does not exist in the target month into the following calendar month, «el plazo concluirá el primer día hábil del siguiente mes de calendario», so a Mexican application published 31 May 2026 closes on 1 July 2026, not 30 June. The field reported unchanged for that, which reads as “a calendar was consulted and this date was already a business day” about a date that had just been moved a month. Read it exactly as you read moved: the close was checked against the office’s calendar, and something moved it. The maintenance engine’s due_date_adjustment and grace_expiry_adjustment have carried this value since 3 September; the opposition field is now the same four-value set. not_checked still wins where the calendar could not be consulted. The overflow’s “following month” half is arithmetic and always applies; its “first business day” half needs the office calendar. A Mexican close past the last pinned IMPI acuerdo therefore stays not_checked rather than claiming an overflow was resolved to a business day. The 20 day indeterminate band is keyed on that same check, so it is unaffected. Maintenance rows follow the same precedence: a Mexican due_date_adjustment or grace_expiry_adjustment past the last pinned acuerdo now reports not_checked where it reported month_end_overflow, and the date still carries the overflow. Reindex required. close_adjustment is baked into search documents at index time, so Mexican records whose window closes on a month-end overflow carry unchanged in search until a full reindex runs. No DATE moves: this is a marker correction only.

September 23, 2026: an absolute statutory ceiling is never rolled past

A prosecution due date clamped to a statutory ceiling is served on the ceiling, closed day or not. When an office states a response deadline later than its own statutory maximum, Signa emits the maximum instead. That date was then put through the weekend and holiday roll, which could walk it PAST the wall: a §66(a) provisional refusal issued 28 May 2026 has a six-month ceiling of Saturday 28 November 2026 under 37 CFR 2.62(a)(1)(ii), and POST /v1/deadlines/compute returned Monday 30 November, a day on which the response is already untimely. It now returns 28 November. The same guard already applied to the extended due date; it applies to the base date now too, which is the served date for any rule with no extension ladder. due_date_adjustment reports not_checked when the roll result was discarded. A date served on the ceiling did not take the roll, so reporting moved (or unchanged) claimed a business-day finding that was never made. This affects the statement-of-use chain, where the ladder lands exactly on the 36 month wall: a notice of allowance issued 10 January 2023 with all five extensions still has an effective due date of Saturday 10 January 2026, and now reports not_checked rather than moved.

September 23, 2026: the Australian Christmas close-down is no longer projected

IP Australia’s Christmas close-down is declared one year at a time, and Signa now treats it that way. The Canberra office’s excluded days come from the Director General’s annual declaration under Trade Marks Act 1995 s 223A, the Office Manual Part 2.1 defines them as exactly that. Signa held one such declaration, for 2026, and was computing its 25 December to 1 January close-down for every year through 2101. Dates in a year with no pinned declaration move EARLIER. Only the days a declaration actually names are closed now; the ACT public holidays this calendar computes from the law (New Year, Australia Day, Canberra Day, Easter, ANZAC, Reconciliation Day, King’s Birthday, Labour Day, Christmas and Boxing Day with their in-lieu Mondays) are unaffected and still roll. A renewal grace expiry on 24 December 2027, for example, is served on Wednesday 29 December 2027 rather than on 3 January 2028. due_date_adjustment, grace_expiry_adjustment and close_adjustment report not_checked for Australian dates outside 2026. That is the honest answer: the deterministic roll still applies and can only be early, but no declaration has been read for that year. Australian renewal DUE dates are unaffected either way, they never roll. Reindex required. One opposition window in our frozen sample of real Australian oppositions moves (publication 29 October 2024, close 2 January 2025 to 30 December 2024). Opposition windows are baked into search documents at index time, so Australian marks published in late October to December carry the old close in search until a full reindex runs.

September 23, 2026: EUIPO closure days are pinned back to 2023

Signa now holds the EUIPO Executive Director’s non-working-day decision for every year from 2023. Decision EX-22-10 of 20 December 2022 (for 2023) and EX-23-11 of 20 November 2023 (for 2024) join EX-24-9 and EX-25-16 in the evidence pack, so the euipo_alicante calendar covers 2023 to 2026 instead of 2025 to 2026. EU dates in 2023 and 2024 now roll against the decision that governs them. Until today those years sat outside the calendar’s pinned coverage and took the deterministic roll, weekends only, reported not_checked. They are verified now, and due_date_adjustment / close_adjustment report moved or unchanged for them. Dates move LATER where a decision closes the office: Article 1 lists 1 April 2024 (Easter Monday), 11 April 2024 (Santa Faz), 23 to 31 December 2024 and 25 to 29 December 2023, none of which the weekend rule sees. Later is the correct direction here, the Office states it was shut, so the earlier answer named a day on which nothing could be filed. In our frozen sample of 8,000 real EU oppositions, 358 window closes move (all later, by 1 to 11 days) and 81 oppositions that had been scored as filed after the close are now correctly inside it. Reindex required. Opposition windows are computed at index time and baked into search documents, so EU marks published in 2023 and 2024 carry the old close date in search until a full reindex runs. POST /v1/oppositions/compute and POST /v1/deadlines/compute are recomputed per request and are correct immediately. Nothing outside 2023 and 2024 changes: the 2025 and 2026 lists are untouched, and 2027 onward still has no pinned decision and still takes the deterministic roll. No rule_id changed.

September 23, 2026: dates outside a calendar’s pinned coverage are rolled again

A deadline that falls outside an office calendar’s pinned coverage is no longer served on a Saturday. Bounding the annual-notice calendars to the instruments actually pinned (Mexico through 30 November 2026, Denmark and France through 31 December 2026, EUIPO to its two Executive Director decisions, WIPO to Information Notice 40/2025) was right about the data and wrong about the answer: every engine read “outside coverage” as “do not roll at all”. A Mexican renewal reached from an ordinary 2025 filing came back due on Saturday 16 June 2035. Those dates now take a deterministic roll: weekends, plus the fixed holidays the calendar computes from the law rather than from a yearly notice. An annual notice or acuerdo can only ever ADD closure days, so the office’s true reopening is at or after the deterministic answer, which means this can be early and never late. The Mexican renewal above is now due Monday 18 June 2035. due_date_adjustment and close_adjustment still report not_checked for these dates, and that is the point: the date is the best safe date, the marker says nobody verified the year’s closure list. Nothing changes inside a calendar’s pinned coverage, where the answer is still moved or unchanged. Opposition windows: an unverified close inside the 20 day rollover band is indeterminate, however it got there. A close date that sits inside coverage but whose rollover walk runs past the end of the pinned data is now treated exactly like one outside coverage: within 20 days of an unverified close, POST /v1/oppositions/compute reports the window open under serve_not_checked and raises the coverage error otherwise. Before this, a EUIPO window published 30 September 2026 read closed on 31 December while the same document was bucketed open in search. Denmark and France gained a coverage FLOOR. Their closure lists are pinned for 2026 only and neither is computable from the statutory holidays, so 2024 and 2025 dates now report not_checked (and take the deterministic roll) instead of claiming a verified unchanged on days those offices were in fact shut. The legacy US office-action rule cites a point-in-time URL. uspto_domestic_oa_response@legacy and uspto_domestic_suspension_inquiry_response@legacy quote the 2015 text of 37 CFR 2.62(a), the six month period. Their url pointed at the current eCFR section, which reads three months and contradicted the quote beside it. It is now the immutable govinfo 2015 annual edition, which is the document the evidence pack actually pins. An opposer’s own marks now list the oppositions that opposer filed. Until now a TTAB proceeding was attached only to the mark it was filed against, so GET /v1/trademarks/{id}/proceedings on a prior registrant’s mark returned nothing about the cases that registrant brought. The USPTO’s TTAB feed names the marks on both sides, and we now link all of them. Every proceeding row carries a new required field, trademark_role:
  • contested: the proceeding targets this mark (the opposed application, the registration under cancellation, the appealed application).
  • asserted: the opposer or petitioner pleaded this mark as a prior right.
It appears on GET /v1/proceedings items, GET /v1/proceedings/{id}, and GET /v1/trademarks/{id}/proceedings items, and all three accept a trademark_role filter. GET /v1/proceedings also takes trademark_role as an aggregation. GET /v1/proceedings/{id} gains trademarks[], every mark in the case with its role, so the opposed application and the pleaded registrations come back in one call. The trademark stub on that response carries trademark_role too. The MCP tools get_trademark_proceedings and list_proceedings take the same filter. Two consequences to plan for. A mark’s proceedings list now includes cases where the mark was asserted, not only cases against it; pass trademark_role=contested for the filed-against view. And one proceeding returns one item per linked mark, so a search by proceeding_number can return several rows that differ only in trademark_id and trademark_role. On the trademark detail, proceedings_count is now an object with the same split, { "contested": 1, "asserted": 40 }, instead of a single integer. Both keys are always present. A single total would have hidden which side a mark is on, which is the question a clearance memo is asking. trademark_role is distinct from parties[].role and the party_role filter, which describe the named parties (opponent, petitioner, respondent), not the marks. Existing rows read as contested. The asserted side is populated for USPTO from the TTAB bulk feed; other offices link the opposed mark only.

September 21, 2026: One row per TTAB opposition on US marks

A US mark opposed or petitioned for cancellation no longer shows two rows for the same proceeding. The USPTO bulk feed carries only a flag for a pending opposition or cancellation, and we stored it as a numberless pending row. When the TTAB docket for the same mark arrived with its proceeding number and parties, both rows stayed. GET /v1/trademarks/{id}/proceedings and GET /v1/proceedings?trademark_id= returned the pair, and proceedings_count on the detail counted both. The flag row is now dropped as soon as a numbered proceeding of the same type exists on the record, and it is not written again while the flag stays set. A mark whose docket we have not matched yet still shows the flag row, since it is the only signal until then. The existing pairs in production are removed in the same release.

September 18, 2026: TTAB proceedings, and how to read them

Trademark Trial and Appeal Board proceedings have been in the API since March. Oppositions, cancellations, ex parte appeals, concurrent-use cases and extensions of time to oppose are ingested daily from the USPTO’s TTAB bulk feed, with rendered decisions from the TTAB Reading Room and per-proceeding detail from TTABVUE. Today that is about 85,000 US proceeding rows on 69,000 marks, refreshed every morning, alongside opposition records from EUIPO, CIPO, IP Australia, IPOS and the Spanish office. This entry exists because the feature shipped without one. Three endpoints serve it, all on trademarks:read:
  • GET /v1/trademarks/{id}/proceedings lists the proceedings a mark is party to, each with parties[].
  • GET /v1/proceedings searches across marks. One filter is required: trademark_id, proceeding_type, status, q (a party name), party_owner_id, party_entity_id, party_role, office_code, contested_class or a filed_date / decision_date range. Aggregations cover outcome, party_role, nice_class, office_code and filed_year.
  • GET /v1/proceedings/{id} returns one proceeding with its parties and the mark it belongs to.
Each proceeding carries proceeding_type, proceeding_number (the TTAB case number, for example 91278456), status, outcome, filed_date, decision_date, decision_outcome (the Board’s own wording) and duration_days. On the trademark detail, proceedings_count says how many there are on each side, and has_proceedings=true narrows a search or list to marks with at least one. The opposition tracking guide walks through a monitoring setup. Four limits to know before you build on it:
  • A proceeding is attached to the mark it was filed against. An opposer’s own marks do not list the oppositions that opposer filed. To profile an opposer, search by party instead: GET /v1/proceedings?q=<name> or party_owner_id=<own_…> (correction, October 1, 2026: party_owner_id returns no results until parties are linked to owners; use q). Decided cases from the Reading Room are attached to every party’s marks.
  • Many filed_date values are null. We trust only the filing date TTABVUE states for the proceeding; the bulk feed’s dates proved unreliable, so rows we have not yet confirmed carry no date and no duration_days. The default sort is -filed_date, so those rows come last.
  • Parties are names. parties[].name is the name as filed, and owner_id is set only where it resolved to a known owner.
  • There is no filing-by-filing docket, and no events or webhooks fire on a proceeding change. Poll the list, or watch the mark’s status.challenges for opposition_pending and cancellation_pending.
To look up a proceeding by USPTO serial number, resolve the mark first: GET /v1/trademarks?application_number=90839902&offices=US, then call its proceedings list. POST /v1/trademarks/batch accepts many serials at once.

September 14, 2026: Consistent trademark detail validators

Trademark detail responses now label their ETag as weak (W/"…") on both 200 OK and 304 Not Modified. The validator tracks equivalent trademark content; the per-request request_id means two otherwise unchanged responses can contain different bytes. This also gives edge-compressed and identity responses the same semantic validator without guessing the selected encoding. Send the full returned value in If-None-Match. Previously issued strong validators still match unchanged resources, and the response returns the weak form. Projections, language, derived data and citation counts continue to participate in cache invalidation. See Caching & ETags.

September 14, 2026: Renewed marks stop showing the paid renewal cycle on US §8/§9 and MX renewals

A registration whose register expiry has already moved to the next term no longer carries its previous renewal as a live deadline, on every rule that ends a term. The maintenance engine has always dropped a renewal cycle that the office’s own stated expiry says was paid, but it recognised only the plain renewal and international_renewal rules. Two rules end a term under a different name and were missed:
  • US Section 8 plus Section 9 (combined_renewal_and_use). A mark registered in 2016 and renewed through 2036 still listed the satisfied 2026 cycle, in grace and apparently actionable, for the six months after that date.
  • Mexico’s combined renewal and declaration of use (mx_renewal, also combined_renewal_and_use, national route). A renewed Mexican registration lost its paid cycle the same way. Madrid designations of Mexico renew centrally at WIPO under renewal and were never affected.
The suppression now covers every term-end rule, so the paid cycle disappears from derived.deadlines on GET /v1/trademarks/{id}, from GET /v1/deadlines, from the portfolio deadline list and its iCalendar view, and from POST /v1/deadlines/compute. POST /v1/reconcile already scored the stated cycle rather than the paid one, so the two now name the same occurrence instead of disagreeing. Rows typed renewal and international_renewal are unchanged. They were already inside the suppression, and their output is byte for byte what it was. Section 8 declarations on their own, Section 15 affidavits and every other non-renewal row are untouched too, since they are filings inside a term rather than the term end. A mark that has not been renewed still shows its open cycle for the whole window and grace period, because the register expiry is that cycle’s own due date and there is nothing to suppress. And POST /v1/deadlines/compute with include_missed: true still returns the full history, including the paid cycle, which is what a docket audit needs. One thing to check in your integration. Every deadline surface computes over a finite horizon: ten years for derived.deadlines on trademark detail, five for GET /v1/deadlines, for the portfolio deadline list and for its iCalendar feed, and whatever you ask for on POST /v1/deadlines/compute. For a mark renewed within the last few months, the paid cycle is now gone and the next term end can sit beyond that horizon, so any of those can come back empty where they previously held one row. A mark registered 1996-06-01 and renewed through 2036-06-01, read on 2026-05-01, is the shape: the paid 2026 cycle is suppressed, and the 2036 cycle falls on 2036-06-02 after the weekend roll, thirty two days past the ten year horizon, and roughly five years past the five year one. It is a well formed empty array, not a missing field, and the mark’s own expiry_date still carries the register’s stated term end. Read the array rather than assuming it has at least one entry. A register value we cannot place on the statutory ladder no longer suppresses a US or Mexican combined cycle. A stated expiry has to fall within about a month of a real cycle on the rule’s ladder for us to treat it as evidence that the cycle before it was paid. On combined_renewal_and_use (US Section 8 plus Section 9, and the Mexican renewal), that recognition is the whole test: a register carrying a term end the rules cannot produce, for example fifteen years after registration on a ten year ladder, used to delete the mark’s real, live obligation from the schedule, and now leaves it alone. Those marks show the cycle actually in force, and POST /v1/reconcile reports the register value as differing from the computed one. Rows typed renewal and international_renewal behave differently here, and deliberately so. For that family an office-stated renewal date is authoritative, so the engine rebuilds the rule’s cycle series through it rather than measuring it against the statutory ladder: an Indian mark whose priority date no register field carries legitimately sits months off that ladder. Taking the office at its word means every cycle before the stated date is still treated as paid, whether or not the date lands near a computed cycle. A register value far enough out that the schedule cannot reach it therefore yields an empty forward schedule on those rules, and POST /v1/reconcile reports the renewal field with a computed_value of null and a computed_unavailable_reason of insufficient_data, rather than a disagreement. The verdict on that field is then scored against the register alone: agrees when your docketed date matches the register, caller_differs when it does not. (insufficient_data is the verdict itself only when the register carries no date either.) That is unchanged from before this release.

September 14, 2026: Docs and spec alignment: rule catalogs join Filing & docketing, alpha labels, monitoring status reference

The rule catalogs now live next to the endpoints that use them. GET /v1/deadline-rules is tagged Deadlines and GET /v1/opposition-rules is tagged Oppositions in the OpenAPI spec, both inside the Filing & docketing tag group, and their reference pages sit under Filing & docketing, Deadlines, after the compute pages. Nothing about the endpoints changed: same paths, same responses, same free reference pool. Only the grouping moved, so a client generated from the spec files the catalogs with the deadline and opposition workflows instead of a separate Reference Data section. If your generator names client classes after tags (openapi-generator, NSwag), the two catalog operations move from the Reference Data class to the Deadlines and Oppositions classes; regenerate and update those two call sites. GET /v1/monitoring/status has a reference page. The endpoint had a guide but no API-reference entry. The new page, under Monitoring, Watches, documents the two halves of the response: watches is your organization’s rollup by health state, and offices[] is Signa’s global per-office ingestion freshness, identical for every organization. It also states plainly that slo_hours is Signa’s internal freshness target for computing pipeline_status, not a published SLA. Screening, compare, listing checks and image search are labelled alpha. These endpoints run on internal and design-partner keys during internal testing and their request and response shapes can still change. The docs pages and spec descriptions now say alpha rather than beta. Email support@signa.so to join the early access list. Analytics navigation is simpler. Market, office and classification analytics are grouped under one Filing Analytics heading; party analytics stay their own group. The rate-limits page inventory lists only published endpoints.

September 11, 2026: Reconcile becomes a docket audit (verdict_detail)

POST /v1/reconcile gains an opt-in three-source verdict. Send verdict_detail: true and every found item adds field_verdicts[] (your value vs the register vs the rulebook-computed schedule, with a seven-value verdict and full rule provenance), a computed context block and a lookup identifier echo. A new your_fields.docketed_deadlines[] input lets you audit the maintenance deadlines you have on docket against the computed schedule. See Three-source verdicts. Entirely additive and off by default: without the flag, responses are byte-identical to before, and with the flag, fields[], result and mismatch_count keep their exact v1 values. Billing is unchanged either way (1 unit per item). One error-path nuance: sending docketed_deadlines without the flag is a 400 validation_error whose message now names the flag requirement instead of the generic unknown-key rejection.

September 11, 2026: Fee endpoints accept platform office codes

GET /v1/fees and POST /v1/fees/estimate now take the office spellings the rest of the API takes. office, and each entry in designations[], used to accept only the WIPO ST.3 codes WO, US, EM and GB, plus WIPO as an alias for WO. They now also accept the platform office codes USPTO, EUIPO and UKIPO, and the permanent EU alias for EM, in any case, exactly as GET /v1/trademarks?offices= does. A request that used to come back with an empty catalog or an unsupported_office line only because of how the office was spelled is now priced. The change is additive, and it is resolution only. Responses echo the canonical ST.3 code, so {"office": "USPTO"} returns "office": "US". No amount, currency or catalog row changes for any request that was already priced, and an office with no verified schedule still returns an empty catalog or an explicit unsupported_office line rather than a guessed amount. Two spellings of one designated office now collapse to one code before the uniqueness check, so designations: ["EM", "EU"] is rejected as a duplicate instead of being counted twice. dataset_version on POST /v1/fees/estimate changes with this release because it covers estimator semantics as well as the fee rows. The rows themselves are untouched.

September 6, 2026: Portfolios are public

Portfolios are now a documented resource family. The nine portfolio operations (create, list, retrieve, update, delete, add and remove trademarks, and the JSON and iCalendar deadline views) appear in GET /v1/openapi.json under a Portfolios tag, grouped under “Filing & docketing”, with reference pages and a portfolios guide. Nothing about the endpoints themselves changed: same paths, same portfolios:manage scope, same read metering (1 unit per request, including writes and calendar downloads), same plan gating. The catalog operations GET /v1/classifications, GET /v1/classifications/{classNumber} and GET /v1/goods-services also move from the Reference Data tag to Classification, which is where the rest of the classification surface already lives. Tags are documentation grouping only; no path, parameter or response shape changed. Three error types that portfolios return are now in the error reference: 409 resource_quota_exceeded, 409 portfolio_in_use and 422 portfolio_too_large. The TypeScript SDK’s generated types caught up with the published spec. @signa-so/sdk 0.12.0 regenerates api-types from the same spec build the published document uses. That adds 37 operations and 21 schemas, and removes nothing. Nine operations and two schemas are the portfolios surface. The other 28 operations and 19 schemas (watches, alerts, webhooks, events, monitoring status) were already published in GET /v1/openapi.json but were missing from the generated types, because SDK codegen ran against a narrower build of the spec than the one we publish. No existing operation or type changed, so the update is additive for every consumer.

September 5, 2026: Auth hardening, plan_gated, prefixed watch filters

Three visible changes from the auth and tenancy hardening pass (the first and third have been live since 2 September; the watch-filter change lands today). None of them alter a successful response. 403 plan_gated replaces a misleading 429. Calling a capability that is not on your plan at all (for example image search on free) used to return 429 rate_limited with retry_after: 0, which sent SDK retry loops spinning. It now returns 403 plan_gated with endpoint_type naming the capability and retryable: false. See the error reference. Watch filters echo prefixed IDs. query.filters.trademarkIds, ownerId, attorneyId and firmId on every watch response (REST and MCP) now come back as tm_* / own_* / att_* / firm_*, whichever form you sent. Input still accepts both, so nothing you send changes. Stricter bearer parsing, clearer outages. Authorization is single-valued (RFC 7235): a comma-joined pair of credentials is a 400. The scheme is case-insensitive. A missing header gets a bare WWW-Authenticate: Bearer challenge with no error code (RFC 6750 §3.1). When Signa’s own token verifier or JWKS is unreachable, MCP requests get a retryable 503 service_unavailable instead of being told the token is invalid.

September 4, 2026: nine deadline rules relabelled, and consequence_if_missed is an open string

Nine maintenance rules changed the consequence_if_missed string they serve. No due date moved, no window opened or closed differently, and no rule was added or removed. Only the label changed: each of these now names the mechanism the office’s own pinned provision prescribes. The rules are bx_renewal and mx_declaration_of_use_3yr (irrevocable_loss to expiration), ch_renewal (irrevocable_loss to removal_from_register), de_renewal, dk_renewal and eu_renewal (cancellation to removal_from_register), fr_renewal and pl_renewal (cancellation to expiration), and th_renewal (removal_from_register to expiration). This shipped with no deprecation window, deliberately. consequence_if_missed is an open string and not an enum: the documented vocabulary is the set of values in use today, and Signa edits a rule’s wording whenever a better reading of the primary source arrives. Branch on rule_id, which is stable and permanent, or on the structured fields that carry the arithmetic, and treat this field as display text. The full before-and-after table is in the deadline rules guide.

September 3, 2026: prosecution deadlines are served outside calendar coverage

A prosecution deadline is no longer withheld because its office calendar cannot check the date. Bounding euipo_alicante to the two Executive Director decisions actually pinned (2025 and 2026) had a consequence we did not intend: every EU office action mailed before 2025, and every one mailed from 1 November 2026 onward (a two-month period lands in 2027), came back insufficient_facts with reason holiday_calendar_out_of_coverage and no date at all. The same held for US office actions before 1985. Silence on a deadline whose miss abandons the application is the worst possible answer. Those cases now return outcome: "computed" with the raw statutory anniversary. An office action mailed 10 January 2024 at the EUIPO reports due_date: "2024-03-10"; one mailed 1 November 2026 reports "2027-01-01". This matches what the renewal engine (due_date_adjustment) and the opposition engine (close_adjustment) have always done. An un-rolled date is never LATER than the true deadline, so it can be early but cannot cause a missed one. New field: due_date_adjustment on every prosecution deadline. It tells you which kind of date you are holding, using the same vocabulary as the renewal rows:
  • moved: the office calendar was consulted and rolled the date forward off a day the office is shut.
  • unchanged: the calendar was consulted and the date was already an open day.
  • not_checked: no calendar verdict stands behind the date. Either the date falls outside the calendar’s pinned coverage, the rule ships without a roll rule, or the office stated the date itself (a stated deadline is published exactly as stated and never rolled). Treat it as the raw statutory anniversary and confirm before relying on the exact day.
  • null: no date was produced at all.
holiday_calendar_out_of_coverage remains in the reason vocabulary but is now a backstop for a calendar-integrity failure rather than the ordinary out-of-coverage answer. No shipped rule reaches it today. close_adjustment on a trademark summary row is no longer nullable. The same marker was declared nullable on the summary row’s opposition_window and non-nullable on the detail tier’s derived.opposition_window. It can never be absent while its parent object exists, so the two now agree and the nullability sits where it belongs, on opposition_window itself. If you null-checked the field, that check is now dead code; nothing you were reading changes value. Search and opposition-compute deliberately disagree for 20 days after an un-rolled close. Where close_adjustment is not_checked and the close is within the last 20 days, search buckets the mark as open (a rollover could only have pushed the close later) while POST /v1/oppositions/compute reports closed against the un-rolled date. Search’s reading is the safe one. Search documents in that band also now carry the un-rolled close rather than no opposition window at all; a full reindex populates them.

September 3, 2026: France, Finland and Poland Madrid designations get opposition windows

Three new rules. An international registration designating France, Finland or Poland had no opposition window at all: POST /v1/oppositions/compute, the derived block, GET /v1/opposition-rules and watch diagnostics all returned nothing for those rows. fr_opposition_madrid, fi_opposition_madrid and pl_opposition_madrid now answer. France, two months from the WIPO Gazette. CPI art. R. 717-1 applies the whole domestic opposition procedure to an international registration extended to France, and art. R. 717-5 names the publication the art. L. 712-4 two months run from: WIPO’s Gazette, not any INPI republication. There is no first-of-the-following-month offset, unlike Switzerland and Germany. INPI’s own directives work the case: an IR published in Gazette 2019/23 of 20 June 2019 has an opposition period expiring 20 August 2019. Every other mechanic is the domestic one by statute rather than by copy, including the art. R. 718-2 same-numbered-day arithmetic, the roll off weekends, jours fériés and INPI closure days, and the extra month for the exposé des moyens. One documented limit, and it is a hard gate. The rule reports effective_from: "2009-01-01" and applicable_from_date: "2009-01-01". The version of art. R. 717-5 in force before that date ran the period from the first day of the month after INPI received the Gazette, an internal office event that no register record carries. We decline that era rather than guess it, so a French designation published before 2009 comes back supported: false with unsupported_reason: "unsupported_office" and the rule identity intact, effective_from naming the boundary. Finland, two months from PRH’s own publication. Tavaramerkkilaki 544/2019 92 § 5 mom. has PRH publish the international registration in the same words 24 § uses for a national one, and 88 § 2 mom. applies the Act to an IR except where the Madrid chapter says otherwise, which it does not for opposition. So 32 §‘s two months from the publication day carry over, with the 150/1930 month-end clamp and the roll off a pyhäpäivä or a working Saturday. PRH’s own gazette confirms it: record W202600336 is an international registration with oppositionPeriodStartDate equal to its publication date. Poland, three months from the BUP announcement. PWP art. 152^1a ust. 1 has UPRP announce a designation of Poland in the Biuletyn Urzędu Patentowego without delay, and art. 152^6a ust. 1 gives an earlier-right holder three months from that announcement, non-restorable. The Biuletyn states the same sentence for both routes. The window opens the day after publication and closes on the same-numbered day three months later under KPA art. 57 § 3, rolling off statutory non-working days and Saturdays under § 4. The rule reports effective_from: "2016-04-15", the commencement of art. 152^6a: before that date there was no pre-grant opposition against a designation of Poland at all. Which publication your date is. All three rules declare it, so the publication_date_kind guard applies. FR needs wipo_gazette; FI and PL need office_journal. Send the other one and the response is status: "unknown" with null dates and the rule’s identity intact, rather than a date you should not act on. Omit the field and nothing changes. Reindex required after the backfill. These windows appear on documents that carry none today, and opposition_window_opens / opposition_window_closes are baked into search documents at index time. Request-time surfaces (POST /v1/oppositions/compute, the derived block, the SDK) are correct the moment this deploys. The opposition_status and opposition_closes_after filters will not see the new windows until French, Finnish and Polish Madrid designations carry an office publication date from the designation-publication backfill and are reindexed. No window we already serve MOVES: no publication date is reinterpreted and no existing pair of dates changes. One thing that does change shape: opposition_window stops being null for WIPO-feed legs. A designation leg that reaches us through the WIPO feed carries office_code = "wipo" with the designated country in jurisdiction_code, which never matched a rule keyed on the designated office’s code. Those legs now resolve by jurisdiction, so for EVERY Madrid jurisdiction we model (not only the three new ones), derived.opposition_window turns from null into an object. Until the leg carries an office publication date the object’s dates are all null and status is "unknown", and opposition_rule_version in search documents becomes non-null after the next reindex where it was null before. If your integration reads opposition_window === null as “Signa does not model opposition for this mark”, that inference no longer holds: check status and window_closes instead. A null opposition_window now means only that no rule matched the office, route and publication era at all. No United Kingdom rule yet. A UK Madrid designation still returns no window. UKIPO runs its three months from the UK Trade Marks Journal, and the current Journal source is not available to us to pin, so the rule is held rather than written from an unverifiable source.

September 3, 2026: holiday calendars now stop where their evidence stops

Some deadline dates move EARLIER, and more of them report not_checked. Every office holiday calendar Signa ships now advertises coverage only as far as the instruments actually pinned behind it. Eight of them are built from a document the office issues once a year: a decision, a notice, an acuerdo, a proclamation, an office memorandum. Those now stop at the last one pinned instead of projecting forward: Beyond those horizons nothing is guessed. A renewal or grace date comes back UNROLLED with due_date_adjustment / grace_expiry_adjustment set to "not_checked", and an opposition window is served with its close on the exact statutory day. Unrolled is never LATER than the true date, so a date we serve can be early but cannot cause a missed deadline. The calendars that are genuinely rule-computed (US, Canada, Germany, Australia, Brazil, Benelux, Switzerland, Finland, UK, Iceland, Norway, Poland, Sweden) still run to 2100, and the lunar ones (Singapore, Thailand, Vietnam, Japan, Korea, Türkiye) to 2030, unchanged. EU: the invented years are gone, and EU dates in 2024 and earlier are no longer rolled. Superseded September 23, 2026: 2023 and 2024 now roll against the EUIPO decisions for those years. euipo_alicante carried closure days for 2024 and for 2027-2030 that no Executive Director decision states. The 2027-2030 entries were labelled “estimate” and moved deadlines LATER: a day after Ascension, in-lieu Mondays, 4 January 2027, 6 December in four different years, and the two decisions that ARE pinned falsify the pattern they were derived from (EX-24-9 closes for Ascension, Schuman Day and the Assumption; EX-25-16 closes for none of the three and adds Santa Faz, 12 October and 2 November). The 2024 block said “per prior EX decision” and no such decision exists in our evidence. All of it is deleted. Consequences, both directions:
  • EU opposition closes for 2027 and later are no longer rolled. A window whose close lands on a weekend or a 2027 Spanish feast is now served on the raw statutory date. Example: an EU application published 30 November 2026 closes 28 February 2027 rather than 1 March 2027.
  • EU dates before 2025 are outside the calendar. An EU office-action response deadline computed from a 2024 mailing is no longer rolled against the unpinned 2024 block. Superseded the same day: this originally returned insufficient_facts with reason holiday_calendar_out_of_coverage. It now returns the un-rolled statutory date with due_date_adjustment: "not_checked". See the entry above.
Mexico: December of the last pinned year is honest about being unknown. IMPI declares each year-end shutdown in the FOLLOWING year’s acuerdo, so the acuerdo for 2026 states every día inhábil of 2026 except the December closure. mx_mexico therefore stops on 30 November 2026. Before this change, an MX opposition window closing 22 December 2026 was served as a working day and reported closed on 24 December, while IMPI was in fact shut. It now reports window_not_computable until the acuerdo covering December 2026 is published. A roll can no longer walk off the end of a calendar. The coverage check ran only on the date being rolled, not on the days the roll walked through. A deadline on a listed year-end closure could therefore step into the following, uncovered year, where every day looks open, and stop on the first of January. WIPO 31 December 2026 reported 1 January 2027 as moved; DKPTO 28 December 2026 reported 4 January 2027. Both now report not_checked and serve the unrolled date. Mexico closes on 25 December. mx_mexico was missing Christmas Day from its recurring días inhábiles, although the one pinned acuerdo that lists a whole year without folding December into a closure block (DOF 5580658) ends «DICIEMBRE Viernes 25». MX deadlines falling on 25 December now roll to the next working day, LATER by one to four days, in every covered year. Iceland: no change, and now only one story about why. 24 and 31 December stay closed on is_iceland, on Hugverkastofan’s own December 2020 notice that the office is shut all day and that deadlines falling there move to the next opening day. Five documents still described these as open days under a superseded reading; they now all state the ruling that shipped. Þorláksmessa (23 December) is declared year by year and stays OPEN. No date moves. Reindex needed for EU and MX opposition windows. Opposition windows are baked into search documents at index time. EU documents whose window closes in 2027 or later, and MX documents whose window closes in December 2026, carry the old rolled close until the affected records are reindexed. Request-time surfaces (/v1/oppositions/compute, /v1/deadlines/compute, the derived block) are correct on deploy. DK, FR, PH and IN opposition windows move only for close dates past their horizons; reindex those offices with the same pass.

September 3, 2026: close_adjustment on every opposition window

New field: was this close date checked against a holiday calendar? close_adjustment now appears on POST /v1/oppositions/compute, on the derived.opposition_window block of a trademark, on the opposition_window of every trademark summary row and on the opposition block of GET /v1/watches/{id}/diagnostics. It reads moved (the close fell on a day the office is shut and was rolled forward), unchanged (the calendar was consulted and the close was already a business day) or not_checked, meaning no calendar stands behind this date. not_checked is not new behaviour, only newly visible. Several office calendars are built from an annual notice (China’s State Council holiday notice, India’s DoPT memorandum, the Philippine proclamations, Mexico’s IMPI acuerdos, WIPO’s non-working-days notice), so a window closing in a year whose notice is not yet published has always been served with raw statutory arithmetic. A rollover can only move a close later, so an un-rolled close is correct-or-early: safe to act on, never a reason to file late. Until today nothing on the wire told the two apart. The opposition_status search filter now treats an un-rolled close as indeterminate. For the 20 days after a not_checked close date, a row counts as open and is excluded from closed, because the rollover that could not be applied may still be holding the window open. not_started and unknown are unchanged, because the opening date is never rolled. Reindex required to populate. The marker is baked into the search index at index time (opposition_close_adjustment, an additive keyword field, so no alias swap, no new index generation). Documents indexed before this release carry no value and are bucketed by their dates alone, exactly as they were before; the indeterminate band applies to them only after a reindex. Every request-time surface (/v1/oppositions/compute, the derived block, watch diagnostics) recomputes and is correct immediately. Also: POST /v1/oppositions/compute declines with window_not_computable in fewer cases. A close falling exactly ON the date you compute as of is now published un-rolled instead of declined: a rollover can only push it later, so the window is open either way. The narrow band that still declines is a close strictly 1–20 days before the as-of date.

September 3, 2026: opposition rule catalog reports both eras

Five new fields on GET /v1/opposition-rules (and the MCP get_opposition_rules): window_change_date, window_starts_on_before, window_months_before, window_days_before and window_ends_on_before. An opposition rule models a regime change inside itself, and the catalog used to serve only the current era, so a client reproducing a close date for a publication before the pivot got the wrong length, the wrong start convention, or both, with nothing on the wire to say so. A publication strictly before window_change_date is governed by the _before fields. All five are null on a rule that has never changed. (A previous entry said era behaviour was already reported through window_starts_on / window_ends_on. It was not; this is the change that makes it true.) One existing value changes: window_ends_on is now era-scoped. bx_opposition opens on the first of the following month only in its pre-1 October 2013 era, so its corresponding_day_of_start describes THAT era. It now reads window_ends_on: null with window_ends_on_before: "corresponding_day_of_start" instead of claiming the current era ends that way. The current BX era anchors the close on the publication day-number and never reads the field. BX is the only affected rule; no computed date moved.

September 3, 2026: rule corrections (CN, PH, CH, CA, DE, MX)

China: the 2027 straddle is served the SHORTER window. The 2026 revision of the Trademark Law cuts the opposition period from three months to two on 1 January 2027 and carries no transitional provision for a period still running on that day: art. 87(2) speaks only of registered marks. The two readings differ by up to a month, so Signa serves the shorter one to the straddling cohort: every CN publication from 1 October 2026 (the first whose three months would still be open at commencement) is now given two months. A mark published 31 December 2026 closes 28 February 2027, not 31 March 2027. A close published too early costs a would-be opponent nothing they can lose by relying on it; one published too late costs the right itself. The call is reversible and will flip the day a transitional notice or the revised Implementing Regulations settles the question. (This supersedes the “Applications published in November and December 2026 keep three months” sentence in the CNIPA entry below.) Reindex: CN opposition windows are index-baked, but CNIPA is a planned office with no indexed records, so there is nothing stale. Philippines: the advisory extension is era-aware. IPOPHL MC 2022-013 introduced the once-only 45-day extension on 30 June 2022. A window that closed BEFORE that date is now served the earlier regime instead: three 30-day extensions on motion, capped at 120 days from publication (MC 16-007 § 12). Display-only: common_extension never affects window_closes. Switzerland (Madrid): the served citation is the operative one. A CH Madrid window used to cite MSchG art. 31(2), whose words run the period “after the publication of the registration”, the national trigger, which this rule never uses. It now cites MSchV art. 50(1), the provision that actually fixes day zero at the first of the month following the WIPO Gazette issue. No date moved; source on the response and sources[0] in the catalog change. Version stamps. ca_opposition, bx_opposition, ch_opposition_madrid and ph_opposition report a new last_verified / rule_version of 2026-09-03. BX and CH had moved served values in an earlier release without moving the stamp. Canada’s two common_extension notes also now name the CIPO practice notice section in full (“section X.1, Extensions of time - benchmarks”) instead of an abbreviation that read as an unfilled placeholder. No computed date moved for CA, CH, BX or DE.

September 3, 2026: maintenance deadline corrections (EU, MX, NO, CA)

Five corrections to POST /v1/deadlines/compute, the derived block on a trademark, and portfolio deadline rows. Maintenance deadlines are computed at request time, so every change below is live the moment it deploys, so no reindex is needed and no stored date changes. A missed EU renewal’s restitutio date moves earlier, by up to two weeks. EUTMR Article 104(2) admits an application for re-establishment “within the year immediately following the expiry of the unobserved time limit”, less the Article 53(3) further six months, so the long stop is the renewal expiry plus twelve months. Signa counted those months from the grace expiry as served, which had already absorbed one Article 69(1) working-day extension, and then extended the sum again. A EUTM filed 21 December 2014 was told its restitutio window ran to 5 January 2026; it runs to 22 December 2025. EUIPO Guidelines Part E §7.4.2 states the rule the fix implements: the extension “applies only once and to the end of the basic period”. The window still OPENS on the grace expiry as served. The same single-extension arithmetic now applies to every restoration window (EU, GB, IN, IS, JP, SG); where the grace expiry did not move, nothing changes. A Mexican Madrid designation now renews on WIPO’s calendar. The renewal of an international registration designating Mexico is paid to WIPO’s International Bureau under Madrid Protocol Article 7 (IMPI never receives it), so Reglamento LPI art. 4o does not reach it. An IR registered 29 February 2004 was given a Mexican due date of 1 March 2014 under art. 4o’s month-end overflow, one day after the international registration had actually lapsed; it is now due 28 February 2014, exactly matching the WIPO row for the same registration, with holiday_calendar: "wipo_geneva". Mexico’s three-year declaration of use is a Mexican filing on IMPI’s own grant date and is unaffected. Norwegian renewal due dates are no longer rolled. Betalingsforskriften § 6 extends a frist, and the § 33 renewal request period is one, so its late end, the grace expiry, still rolls to the next virkedag. The due date is not a frist: it is the end of the registration period, and varemerkeloven § 33 første ledd tredje punktum charges the tilleggsavgift for a request delivered “etter utløpet av registreringsperioden”. A due date served on the Monday would have advertised a surcharge-free filing day after the period had already ended. A Norwegian mark filed 1 May 2016 is due 1 May 2026, not 4 May, and its due_date_adjustment reads not_checked. Grace expiries are unchanged. This is the same treatment Australia has had since the s 223A(1) wiring, and GET /v1/deadline-rules now says so explicitly (below). An office-stated 29 February expiry no longer returns an empty schedule. A mark whose office-reported expiry fell on a leap day could return zero deadlines: a live EUTM two months from expiry, with nothing to file against. Three separate pieces of leap-day arithmetic compounded; all three are fixed, and such a record now returns its renewal row on the office’s own date. Canada: last_renewal_date is a new optional field on compute. Trademarks Regulations s. 159 opens the first post-17-June-2019 renewal window at the period start, and it keys on the renewal, not on the cycle’s due date. A registration whose term ended shortly before that day but whose fee was paid in the grace period on or after it is the s. 159 renewal; the one after it is an ordinary s. 76 renewal. Send last_renewal_date on a compute item and Canada uses it. Omit it and the previous due-date behaviour is unchanged. GET /v1/deadline-rules and the get_deadline_rules MCP tool gain grace_expiry_rolls_only. A boolean, present on every row. When true, the jurisdiction rolls its grace expiry but never its renewal due date, which is what Australia and Norway do. weekend_holiday_rule: true alone could not express that, so a docketing system reading the catalog had no way to tell a scoped roll from a full one. Additive: no existing field changed.

September 3, 2026: China (CNIPA) deadlines and opposition windows

New jurisdiction. POST /v1/deadlines/compute, POST /v1/oppositions/compute, the derived block on a trademark, GET /v1/deadline-rules and GET /v1/opposition-rules now answer for Chinese marks. Three rules ship: cn_renewal, cn_opposition and cn_opposition_madrid. office: "CN" is accepted on the oppositions endpoint and comes back as CN. A Chinese term counts its first day. Under Implementing Regulations art. 12(2) a registration’s ten years run from the day the office approves it and INCLUDE that day, so the term ends the day BEFORE the anniversary: a mark registered 7 March 2016 expires 6 March 2026, not 7 March. The 12-month renewal window and the 6-month grace period are measured from that expiry. Where the anniversary day does not exist in the target month, the expiry is the last day of that month instead: a mark registered 29 February 2020 expires 28 February 2030. Opposition: three months now, two from 1 January 2027. Trademark Law art. 33 gives three months from the preliminary-approval publication (初步审定公告, not the registration publication), counted from the day after and ending on the same day-of-month three months later. The 2026 revision of the Trademark Law cuts that to two months in its renumbered art. 36 and enters into force on 1 January 2027 (art. 87). Both eras are modelled now, selected by the publication date, and each window is served the article that states its own length. Applications published in November and December 2026 keep three months: the revision carries no transitional provision, and that is the non-retroactive reading. Madrid designations of China use a different anchor. CNIPA does not republish an international registration, so the window runs off the WIPO Gazette: Implementing Regulations art. 45(1) opens it on the FIRST DAY OF THE MONTH FOLLOWING the Gazette issue and runs three months to the last day of the third month, which is CNIPA’s own worked example (Gazette 16 January 2012 → 1 February to 30 April 2012). Supply the Gazette issue date as the publication date for these rows. Holiday calendar, and where it stops. Chinese deadlines roll to the first working day when they fall on a statutory holiday, and the calendar is built from the State Council’s annual holiday notice, including the make-up working weekends (调休), where a Saturday or Sunday is declared a working day. A renewal due on Friday 2 January 2026 is due on Sunday 4 January 2026, the first working day, not Monday the 5th. Because each year’s notice is published only the preceding November, coverage runs 2024–2026: dates beyond it are reported unrolled rather than rolled against a guess: renewals with due_date_adjustment: "not_checked", and an opposition window with its close on the exact statutory day. Unrolled means EARLIER than the true date, never later. The one exception is a window that closed within the last 20 days beyond coverage, where a roll could still be holding it open: there the window is returned unsupported_reason: "window_not_computable" with its rule identity intact rather than risk labelling a live window closed. Coverage extends when the 2027 notice is published. Reindex: none needed today. Opposition windows are baked into search documents at index time, so a new rule normally reaches already-indexed documents only after a reindex. Here there is nothing to reindex: CNIPA is a planned office and Signa holds no Chinese records in the search index yet, so no stored value changes and no document can be stale. Request-time surfaces (/v1/deadlines/compute, /v1/oppositions/compute, the derived block, the rule catalogs) answer for China on deploy, and the index-time path will pick the rules up with the first CNIPA ingestion. Should any Chinese records be indexed before then, they would need a reindex to gain opposition_window_opens / opposition_window_closes; nothing they carry would be wrong.

September 3, 2026: Benelux opposition windows before 1 October 2013 corrected

Historical dates change for bx_opposition. The two-month Benelux opposition period has not always run from the publication day. Until 30 September 2013 BVIE art. 2.14(1) counted it “te rekenen vanaf de eerste dag van de maand volgende op de publicatie van het depot”, from the first day of the month FOLLOWING publication. The Protocol of 22 July 2010 (art. I.D) replaced those words with “te rekenen vanaf de publicatie”, and it entered into force on 1 October 2013 (Trb. 2013, 135). Signa was applying the current text to every publication, however old. A Benelux application published on 12 June 2013 was reported as open from 12 June to 12 August 2013 when the window the law gave ran from 1 July to 1 September 2013, a close up to 30 days EARLY. Only publications before 1 October 2013 are affected, every one of those windows is long closed, and no status changes; what changes is the pair of dates we report about them, which matters wherever a historical window is cited in a dispute or an audit trail. The rule carries both the superseded article text and the amending Protocol as pinned, era-bounded citations, so a pre-2013 window is served the text that actually governed it. (This entry originally said GET /v1/opposition-rules reported the era behaviour through window_starts_on / window_ends_on. It did not; those fields describe the current era only. The era fields shipped on 3 September 2026; see the entry at the top of this changelog. BX now reports window_change_date: "2013-10-01", window_starts_on_before: "first_of_following_month" and window_ends_on_before: "corresponding_day_of_start", with window_ends_on: null.) Era selection keys on the publication date, which is the only date either text can be read on. Neither Protocol carries a transitional provision. One documented limit follows: for a mark published between 1 August and 30 September 2013 the old text’s window was still running when the new text took effect, and no source says which governs. We serve the old rule, and therefore the later close, which is the conservative direction for anyone deciding whether they may still oppose. Reindex. Opposition windows are baked into search documents at index time, so pre-2013 Benelux documents keep the old opposition_window_opens / opposition_window_closes values until BOIP records are reindexed. Every affected window is closed and none of them can change opposition_status, so this is low priority and belongs with the next natural BX reindex rather than with a dedicated run. Request-time surfaces are correct on deploy.

September 3, 2026: German Madrid designations get an opposition window

New rule de_opposition_madrid. An international registration designating Germany had no opposition window at all: POST /v1/oppositions/compute, the derived block, GET /v1/opposition-rules and watch diagnostics all returned nothing for a DPMA Madrid row. That was honest, because the rule could not be expressed, but silent, and the deadline it hides is a hard statutory bar. MarkenG § 114(1) puts the WIPO gazette in the place of the Markenblatt publication of a national registration, and § 114(2) starts the § 42(1) three months on the first day of the month following the gazette’s issue month. Because that start is the beginning of a day, BGB § 187(2) counts it and § 188(2) Alt. 2 ends the period the day before the corresponding day: the last day of the third month. A gazette issued in March 2026 opens the window on 1 April 2026 and closes it on 30 June 2026; an issue in November 2026 runs 1 December 2026 to 28 February 2027, which is a Sunday, so BGB § 193 and DPMAV § 18a roll it to 1 March. The fee (250 EUR, plus 50 per further sign) falls due inside the same period, and the window is not extendable. MarkenG § 91(1) sentence 2 bars even Wiedereinsetzung. Worth noting next to the Swiss correction in this same release: Germany and Switzerland start their Madrid windows on the same day and close them one day apart. MSchV art. 2 ends a Swiss period on the corresponding day, BGB § 188(2) Alt. 2 ends a German one the day before. window_ends_on on GET /v1/opposition-rules reports which reading each rule applies. No German source gives a worked example of the end day, so it is derived from the two BGB provisions and cross-checked against the DPMA’s own Richtlinie W 7736, which states the start in the office’s voice; the derivation is recorded in the evidence pack rather than asserted. Reindex. Opposition windows are baked into search documents at index time, and DE Madrid documents currently carry null windows, so the opposition_status and opposition_closes_before / opposition_closes_after filters will not see this rule until German Madrid designations are reindexed. Request-time surfaces are correct on deploy. As for Switzerland, the reindex only becomes meaningful once designation records carry the WIPO gazette publication date the rule anchors on.

September 3, 2026: Swiss Madrid opposition windows close up to 30 days earlier

Computed dates change for ch_opposition_madrid, in the safe direction. The opposition window against an international registration designating Switzerland does not run from the day the WIPO Gazette published the designation. MSchV art. 50(1) starts it on the first day of the month following the Gazette month, and MSchV art. 2 ends a month period on the same-numbered day, so the window closes on the 1st of the fourth month. The IGE publishes the worked example: a Gazette of 19 July 2022 opens the window on 1 August 2022 and closes it on 1 November 2022. Signa was computing “Gazette day plus one month” to “Gazette day plus four months” instead. That is the same answer only when the Gazette date is itself the 1st; for every other issue the close we published was up to 30 days later than the law allows. A Gazette of 15 January 2026 was served a close of 15 May 2026 where the true, non-extendable deadline is 1 May 2026. Later than the truth is the dangerous direction on an opposition bar, so this is a correction customers should re-docket: every Swiss Madrid close moves earlier by nought to thirty days, and every open moves to the 1st of the month. GET /v1/opposition-rules now reports window_starts_on: "first_of_following_month" and window_ends_on: "corresponding_day_of_start" for this rule, and window_starts_offset_months is null. Both enums are new and additive; no existing value changed meaning. Trademark responses, the oppositions compute endpoint, the derived block and watch evaluation recompute the window per request, so they are correct as soon as this deploys. Reindex. Opposition windows are baked into search documents at index time, so opposition_status and the opposition_closes_before / opposition_closes_after filters carry the old arithmetic until Swiss Madrid documents are reindexed. In practice there is nothing to correct yet: a designation is indexed as part of its international-registration family, and IR-family documents carry null opposition windows today, while the Madrid source we ingest publishes no per-designation publication date for the rule to anchor on. The reindex therefore belongs with the work that starts storing the WIPO Gazette publication date for designations, not with this change.

September 3, 2026: Norway Madrid opposition, and a publication-date guard for every Madrid rule

New rule. no_opposition_madrid covers an international registration designating Norway. Patentstyret publishes in Norsk varemerketidende that the IR has effect in Norway (varemerkeloven § 70 annet ledd, varemerkeforskriften § 32), and § 71 første ledd gives anyone three months from THAT kunngjøringsdag to oppose, applying § 26 correspondingly. So every mechanic of the Norwegian domestic rule carries over by statute rather than by copy: the count starts on the publication day itself, the three-month period ends on the corresponding day-number, it rolls off 24 and 31 December, Saturdays, helligdager and likestilte dager under betalingsforskriften § 6, and it cannot be extended. There is no WIPO offset: § 71 runs straight from Patentstyret’s own publication, unlike EUIPO’s Madrid-EU rule. The 18-month Madrid refusal limit is an obligation the office owes WIPO and never changes the three months the parties get. GET /v1/opposition-rules, POST /v1/oppositions/compute (office NO, filing route madrid) and the derived block on a Norwegian Madrid designation now answer instead of returning nothing. One documented limit. The rule reports effective_from: "2010-07-01" and applicable_from_date: "2010-07-01", the day varemerkeloven (the Act § 71 belongs to) entered into force (res. 25. juni 2010 nr. 936). Before it the repealed 1961 Act § 21 gave TWO months from the kunngjøringsdag, an era we do not model on the Madrid route, and serving the modern three months to it would report a close date a month LATER than the law gave. A Norwegian designation published before 1 July 2010 therefore comes back supported: false rather than with a window. No reindex required. This adds a window where there was none; it changes no existing window. Baked opposition_window_opens / opposition_window_closes values in the search index are all still correct. Norwegian Madrid designations pick their new window up at their next natural reindex. A guard against the wrong publication. A Madrid designation has two publications that can fill one date field (WIPO’s Gazette of the international registration, and the designated office’s own journal republication), and different offices run their clock from different ones. Feeding a rule the other one silently produces a plausible-looking, wrong statutory bar. Each Madrid rule now declares which publication it needs, and POST /v1/oppositions/compute accepts an optional publication_date_kind (office_journal, wipo_gazette, office_register, unknown) saying which one your date is. When the two disagree the response is status: "unknown" with null dates and the rule’s identity intact, rather than a date you should not act on. A new nullable reason field on each POST /v1/oppositions/compute item and on the trademark derived.opposition_window block says WHY it is unknown ("publication_date_kind_mismatch" today, null otherwise), so you can tell a contradicted publication kind from a mark that simply has no publication date yet; the field is additive and null on every response that had no reason to carry it. Omit the field and nothing changes. Today EVERY Madrid rule declares its publication: ch, de and fr run from the WIPO Gazette; no, fi, pl, sg, us, ca, au, eu, jp, kr, in and tr run from the designated office’s own journal. Declaring it is not optional in practice. A WIPO-feed leg is resolved by jurisdiction, and the date it carries is the Gazette’s, so a rule that has NOT adjudicated which publication it runs from is refused on that path outright rather than dated on a publication nobody established it uses. The four Asian Madrid rules (jp, kr, in, tr) were adjudicated for this release; each of their statutes names the office’s own gazette and says the WIPO Gazette is not the trigger.

September 3, 2026: EU restitutio, Canada’s transitional renewal window, India’s priority-dated term, and WIPO closure days

Four deadline corrections, all computed at request time. Nothing is baked into the search index, so every one of them is live the moment this deploys and no reindex is involved. The EU now has a restoration deadline. POST /v1/deadlines/compute, GET /v1/deadline-rules and the derived block on an EU trademark return a new restoration row once a renewal has passed its due date, under one new rule_id: eu_restitutio. It runs from the end of the six-month grace period to twelve months after the registration expired, which is what Article 104(2) EUTMR leaves after deducting the further six months of Article 53(3) from the year following the missed time limit, and what the EUIPO Guidelines state in one sentence: the one-year period “starts on the day on which the protection ends and not on the expiry of the further 6-month grace period”. Read the row as an outer date, not as a promise. Restitutio is discretionary: it is granted only where all due care required by the circumstances was taken, it carries a fee, and it must also be requested within two months of the removal of the obstacle, a date no register publishes. No existing EU date moves. Canada’s first renewal after 17 June 2019 opens far earlier than we said. For a trademark that was on the register before that day, Trademarks Regulations s. 159 lets the renewal fee for the FIRST renewal falling due on or after it be paid from the start of the period being renewed, with no six-month early limit, and CIPO says so directly: “there is no restriction on how early the renewal fee for the first renewal after June 17, 2019 may be submitted.” The engine used to report that window opening six months before the due date. window_opens on the affected cycle now moves back to the day of registration or of last renewal, which can be fifteen years earlier. Only that one cycle is affected; the due date, the grace expiry and every later cycle are unchanged, and the window can only widen, so nothing that was filable becomes unfilable. An Indian trademark with a convention priority claim expires earlier than its filing date implies. Trade Marks Act 1999 s. 154(2) registers a Paris or WTO convention application as of the date the application was made in the convention country, and s. 23(1) is expressly subject to it, so the ten-year term of s. 25(1) runs from the priority date, up to six months before the Indian filing. POST /v1/deadlines/compute accepts a new optional priority_date on each item; send it for an IN item and the renewal is computed from it, with trigger_field reading priority_date so the answer says which date it used. Omit it and India falls back to the filing date exactly as before. The field is inert for every other jurisdiction: no other pinned term provision runs from a priority date. Note the current limit: our own stored trademarks carry priority claims in a separate record, so the derived block, portfolio deadline lists and the iCal feed do not yet pass one and still serve the filing-date answer for that cohort, which is the later date. Where the office states an expiry, that expiry already anchors the schedule and the question does not arise. WIPO renewal dates now move off days the International Bureau is closed. Rule 4(4) of the Regulations under the Madrid Protocol extends a period that expires on a day the IB is not open to the public to the first subsequent day it is, and a renewal payment is a communication the IB must receive. WIPO rows now report holiday_calendar wipo_geneva, and a due date or grace expiry that falls on a weekend or on one of the eight days WIPO published for 2026 (1 January, 3 and 6 April, 14 and 25 May, 31 July, 25 and 31 December) is served on the next open day with the adjustment field reading moved. An international registration dated 13 June 2016, for example, was renewable “by 13 June 2026”, a Saturday; the answer is now Monday 15 June 2026. The International Bureau publishes its closure list one year at a time, so the calendar covers 2026 only: dates in any other year are emitted exactly as the Rule 4(1) and 4(2) arithmetic produced them and report not_checked rather than a business-day guarantee we cannot make. Filing-window opening dates are never rolled, on any office. Every value above cites the instrument it comes from, with a verbatim quote and a hash-pinned snapshot, on GET /v1/deadline-rules and on each compute response.

September 3, 2026: Mexican OPPOSITION windows follow the same month-overflow rule, and the overflow is now reported

Opposition close dates change for MX (IMPI). Reindex MX. Earlier today Signa applied Reglamento de la Ley de la Propiedad Industrial art. 4o, párrafo segundo to the Mexican maintenance ladders: a period counted in months that ends on a day the target month does not have runs into the following calendar month and ends on its first business day, rather than clamping to the short month’s last day. The opposition engine kept the clamp, which was stated as a limit in that release. It no longer does. Art. 4o computes «los plazos establecidos en meses o años a que se refiere el artículo 184 de la Ley», and art. 184 LPI (re-enacted word for word as LFPPI art. 21) is the Law’s general period-computation article, not a maintenance-only provision. The one-month opposition period of LFPPI art. 221 is a period fixed in months by the Law, so it is inside art. 4o. An application published on 31 March 2026 now closes for opposition on Monday 4 May 2026, not 30 April: April has no 31st, so the period runs into May, and May 1 is Día del Trabajo with the weekend behind it. A publication on 31 August 2026 closes 1 October instead of 30 September. Publications whose day number exists in the next month are untouched. Every corrected date is LATER than the one Signa served before, so nobody who relied on the old date filed late. GET /v1/opposition-rules gains month_end_overflow on every rule, so a client that recomputes a window from the rule can reproduce the close date. It reads last_day everywhere except mx_opposition. The overflow move is now reported. due_date_adjustment and grace_expiry_adjustment on POST /v1/deadlines/compute gain a fourth value, month_end_overflow. Before this, an overflow that landed on an open day was indistinguishable from a date nothing had happened to: the fields described the weekend and holiday roll only, so they read unchanged. The new value subsumes the roll on such a date, because art. 4o para. 2 names the first BUSINESS day of the following month, so the move into the next month and the roll that completes it are one statutory step. The addition is additive: no existing value was renamed or removed. Opposition windows are baked into the search index at index time, so the materialised opposition_status and opposition_closes_before/opposition_closes_after filters on MX documents are corrected only after MX is reindexed. POST /v1/oppositions/compute and the trademark response recompute per request and are correct as soon as this deploys.

September 3, 2026: Mexican deadlines now roll, month-overflow ends in the next month, and Madrid designations renew on the international registration

Computed dates change for MX (IMPI), on both engines. Reindex MX. Mexican maintenance dates were published raw: a renewal that fell on a Sunday or on a day IMPI declares inhábil was served on that day. Reglamento de la Ley de la Propiedad Industrial art. 4o, the 1994 regulation the LFPPI keeps in force, says otherwise in its third paragraph, and Signa now applies it. A renewal due date, grace end or 3-year declaration-of-use window end that lands on a weekend, on a fixed Mexican holiday or on a día inhábil IMPI has published moves to the next working day, holiday_calendar reads mx_mexico, and the two adjustment fields read moved or unchanged. Filing windows never move: a window that opens on a closed day cannot be filed that day, and moving it would shorten the statutory six months. The same article’s second paragraph fixes a subtler error. When a period counted in months or years ends on a day the target month does not have: a six-month grace counted from a 31st, landing on “31 February”. Mexico does not clamp to the 28th the way most offices do. The period ends on the first business day of the following calendar month. A grace period that used to read 28 February 2033 now reads 1 March; in a leap year, 29 February 2036 becomes Monday 2 March 2036. This is the first office in the corpus to depart from the month-end clamp, and it is behind a per-office flag, so no other jurisdiction’s dates move. The IMPI holiday calendar was rebuilt from the Diario Oficial. It carried a flat “IMPI closes 16 to 31 December, every year” block that no published acuerdo supports. IMPI sets its year-end closure annually: 18 December to 2 January for 2024, 19 December to 3 January for 2025, 22 December to 6 January for 2026. So the old calendar closed four days IMPI works and opened five days it does not, in both directions. It also omitted 5 May and 1 September, which four published acuerdos name. The calendar is now eleven recurring days plus exactly what each pinned acuerdo states, including the one-off closures of 1 October 2024, 12 December 2025, 23 February 2026 and 30 June 2026. Madrid designations of Mexico now renew on the right date. A designation has no independent Mexican term: it expires with the international registration and is renewed centrally at WIPO. The rule that served it was Mexico’s national “renewal plus declaration of use”, which the engine anchored on IMPI’s grant date, and for a designation granted years after the international registration, that is a renewal date up to a decade too late. There is now a separate rule, mx_renewal_madrid, anchored on the international registration date, and a designation whose international registration date is unknown and whose office expiry is not on the record DECLINES with requires_office_date instead of publishing a guess. The declaration of use that follows a Madrid renewal runs three months from the International Bureau’s notice, a date no record carries, so Signa deliberately publishes nothing for it rather than a wrong date. Every Mexican value is now cited to the Diario Oficial de la Federación itself (the primary publication) with a verbatim quote and a pinned snapshot, with the consolidated ordenjuridico.gob.mx copies kept alongside. That includes the eight IMPI acuerdos behind the calendar. Three limits are stated rather than hidden. IMPI publishes each December’s closure in the preceding autumn, so a year with no published acuerdo has no closure in Signa: a date in late December 2026 or later is served un-rolled, which is earlier than the true date, never later. The opposition engine still applies the ordinary month-end clamp rather than art. 4o’s overflow rule, again in the earlier direction. And the overflow move itself is not reported in the adjustment fields, which describe the weekend and holiday roll only. Trademark responses and POST /v1/deadlines/compute recompute per request, so they are correct as soon as this deploys. Opposition windows are baked into the search index at index time, so the materialised opposition_status and opposition_closes_before/opposition_closes_after filters on MX documents are corrected only after MX is reindexed.

September 3, 2026: Australian renewal grace periods roll onto the next open day

An Australian trade mark can still be renewed for six months after it expires (Trade Marks Act 1995 s 79). When the last day of that six-month period falls on a weekend, a Canberra public holiday or IP Australia’s standing Christmas close-down, POST /v1/deadlines/compute and the derived block on a trademark now serve the next day the office is open, and say so in grace_expiry_adjustment (moved) and holiday_calendar (au_australia). Australian grace dates were previously served one to three days EARLY. The renewal DUE date deliberately does NOT move, and this is the only office where the two answers differ. s 223A(1) rolls “the last day of a period provided by this Act (except this section) for doing an act”; the s 79 period is one, reg 21.24A supplies the prescribed circumstance and reg 21.24C, the exclusion list, does not reach a renewal request. The twelve-month renewal REQUEST period is a different animal: it is prescribed by reg 7.3 rather than by the Act, and Schedule 9 item 10 keys the $100-per-month surcharge on the request being made “after the expiry date to which section 79 of the Act refers”: the expiry day itself. Serving a later due date would tell you that you may still renew fee-free on the Monday when the surcharge may already have attached on the Saturday. So an Australian due_date stays on the statutory expiry and reports due_date_adjustment: "not_checked" on every row, whatever day of the week it lands on: no calendar was consulted for it, and unchanged would claim a Saturday is a business day. Nothing else about the Australian rule changed: same rule_id (au_renewal), same ten-year term, same twelve-month window, same six-month grace, same consequence. Three provisions are newly pinned and quoted verbatim next to the field they move: s 223A(1), reg 21.24A, and reg 21.24C in full, so that the absence of a renewal request from the exclusion list is verifiable rather than asserted. Maintenance deadlines are computed per request, so this is live as soon as it deploys and no reindex is required. It supersedes the “Australia is deliberately NOT rolled” note in the entry below.

September 3, 2026: renewal dates roll on closed office days in Norway, France and Iceland, and on BOIP’s own closing days in the Benelux

Four offices join the maintenance rollover: a renewal due date or grace expiry that lands on a day the office is closed is now served on the next day it is open, instead of on the exact calendar date. POST /v1/deadlines/compute and the derived block on a trademark answer with the moved date and say so in due_date_adjustment / grace_expiry_adjustment (moved, unchanged or not_checked) and holiday_calendar. Nothing about a rule id, a window length or a consequence changed; only the served dates. Each office rolls on the provision that governs its own renewal deadline, not on a generic weekend rule. Norway: betalingsforskriften § 6 første ledd (24 and 31 December, Saturdays, helligdager and days the legislation treats as equivalent), extended to varemerkeloven deadlines by § 6 tredje ledd. France: CPI R. 718-2 al. 5, applied to the renewal declaration by INPI’s own renewal directives, which work the example: a mark expiring Saturday 14 May 2022 could be renewed on Monday 16 May with no late-renewal fee. Iceland: Stjórnsýslulög nr. 37/1993 8. gr., which extends a period ending on a general public holiday to the next day the authority is OPEN. Benelux: Uitvoeringsreglement regel 3.9, lid 3. Every one is pinned and quoted verbatim next to the field it moves. Two office calendars were corrected from primary sources in the same change, and both corrections can move a date on their own. The Benelux calendar is now BOIP’s own closing-day list, published as a Regel van de Directeur-Generaal of 3 April 2019, rather than an assumed Dutch national-holiday set. Ten days join it: 2 January, 1 May, Europe Day, the Luxembourg and Belgian national days, Assumption, All Saints, All Souls, Armistice Day and the Belgian King’s Day, and Good Friday LEAVES it, because the rule names it on neither limb and BOIP is open that day. A Benelux deadline falling on Good Friday is therefore due that day, not the following Tuesday. Iceland’s 24 and 31 December STAY CLOSED, and no Icelandic date moves on that account. An earlier draft of this release opened both days: they are public holidays only FROM 13.00 under lög nr. 88/1971 6. gr. (24 December only from 18.00 as a church holiday, lög nr. 32/1997 2. gr.), so the statute alone gives a half day, and no ISIPO closure notice had been found. One was then found: Hugverkastofan’s own December 2020 notice, which says the office is closed on Þorláksmessa, aðfangadagur and gamlársdagur and that every deadline falling in that period moves to the next opening day. The office’s own statement settles the office’s own opening days, so both remain closed, exactly as before this release. See “Philippines, India and Iceland business-day calendars re-sourced” below. Benelux opposition windows DO move, because Good Friday left bx_benelux. Opposition windows are materialised into search documents at index time, so opposition_status and the opposition_closes_* filters carry the corrected dates for BX records only after that office is reindexed. Every trademark response recomputes the window per request and is correct as soon as this deploys, and maintenance deadlines are computed per request throughout, so no reindex is needed for them. Australia was NOT rolled in this change, and the reason was documented rather than hidden: Trade Marks Act 1995 s 223A(1) settles the six-month post-expiry limb but not the due date, and the rollover was one switch that moved both dates. SUPERSEDED the same day by the entry above, which gives the engine a grace-only roll and turns it on for Australia. Two accuracy limits are recorded with the same candour. INPI closure decisions before 2026 were never fetched, so a French date that fell on a pre-2026 closure day is served un-rolled. BOIP publishes any FURTHER closing day for a given year on a page that is not reachable programmatically, so those ad-hoc days are not modelled either. Both under-roll rather than over-roll.

September 3, 2026: EUIPO Article 2 days now extend time limits; consequence_if_missed vocabulary fixed

EU dates move later on four days a year. The euipo_alicante calendar now carries BOTH lists of the Executive Director’s annual decision on non-working days: the Article 1 days on which the Office is closed AND the Article 2 days on which the Office is open but ordinary post is not received (19 March, 23 June, 9 October, 8 December in EX-24-9 for 2025 and EX-25-16 for 2026). Article 69(1) EUTMDR extends a time limit expiring “on a day on which the Office is not open for receipt of documents or on which … ordinary post is not delivered in the locality in which the Office is located … until the first day thereafter on which the Office is open for receipt of documents and on which ordinary mail is delivered”, and the Office’s own decision reads it the same way (EX-24-9 recital (1)(b)). Until now only Article 1 days rolled, which served the earlier date; the served date is now the statutory one. Affected: POST /v1/oppositions/compute and opposition_window for EM marks whose window closes on one of those days (e.g. a Part A publication on 9 July 2026 now closes 13 October 2026, not 9 October), the EU office-action response deadlines, and the watch-evaluator’s opposition windows. Opposition windows are baked into the search index at index time, so indexed EM documents carry the corrected close only after the EU reindex (scheduled with this release). The 2027-2030 Article 2 days are carried on the same estimate basis as the Article 1 days and are replaced each December from the published decision. EU RENEWAL dates move on the same days. An earlier draft of this entry said they did not, on the ground that the EU maintenance config does not business-day adjust. It does now: the same release turns on the roll for EU renewals, so a eu_renewal due date or grace expiry landing on any day the Alicante calendar carries, Article 1 closures and Article 2 ordinary-post days alike, is served on the next open day instead. A mark filed 19 March 2016 was served a renewal due 19 March 2026 and a grace expiry 19 September 2026; it is now due 20 March 2026 with grace to 21 September 2026, because 19 March is San José, an Article 2 day. The direction is later. For an Article 1 day that is unambiguously the safe direction: the Office is shut on the original date, so the served day is the first one on which you can actually file. For an Article 2 day it is a judgement call, and this entry originally overstated it, on 19 March the Office is open, and only ordinary post is not delivered in Alicante. Signa rolls it on the reading of Article 69(1) EUTMDR that the Office’s own decision states (EX-24-9 recital (1)(b)), which covers a day on which “ordinary post is not delivered” as well as a closure. An e-filer can nonetheless file on the original day, so if the Office ever reads Article 69(1) as extending only for post-borne filings, the served date is a day LATER than the true one. That is the unsafe direction, it is bounded at four days a year, and it is now listed in Accuracy limits. due_date_adjustment and grace_expiry_adjustment read moved on those rows and unchanged on the rest, so a row always says whether a calendar was consulted. Renewal dates are not baked into the search index, so no reindex is needed for this half. consequence_if_missed now means one thing per value. The value names the mechanism the office’s pinned provision prescribes: expiration (the right ends by operation of law), removal_from_register (the office strikes the entry as the statutory consequence), cancellation (the office cancels a still-running registration for a missed maintenance filing, US §8/§71), and restorability is said only by the presence of a restoration rule. Nine rules were relabelled to match their pinned text; no date moved: pl_renewal cancellation → expiration (PWP art. 168 ust. 1 pkt 1 “wygasa”), fr_renewal cancellation → expiration (CPI L. 712-1), de_renewal cancellation → removal_from_register (§ 47 Abs. 6 MarkenG “gelöscht”), dk_renewal cancellation → removal_from_register (varemærkeloven § 37 “udslettelse”), eu_renewal cancellation → removal_from_register (Art 53(8) EUTMR “cancel the mark from the register”), bx_renewal irrevocable_loss → expiration (BVIE art. 2.26(a)), ch_renewal irrevocable_loss → removal_from_register (MSchG art. 35(b)), mx_declaration_of_use_3yr irrevocable_loss → expiration (LFPPI art. 233 “caducará de pleno derecho”), th_renewal removal_from_register → expiration (Trademark Act s. 56 deems the registration revoked). irrevocable_loss is retired: no rule serves it. The full vocabulary is in the deadline rules guide. No wire-format change: the field stays a string and no new value was added.

September 3, 2026: Philippines, India and Iceland business-day calendars re-sourced

Three office calendars used for business-day adjustment now rest on the primary instruments that actually set the closed days, and two of them change published dates. Philippines (ph_philippines, used by ph_opposition). The closed days are now transcribed year by year from the presidential proclamations that declare them, Proclamations 368 s. 2023, 453, 514, 579 and 665 s. 2024 for 2024; 727 and 729 s. 2024, 839, 878 and 911 s. 2025 for 2025; 1006 s. 2025, 1189 and 1264 s. 2026 for 2026, together with the statutory fixed days (RA 9492 s. 1, RA 10966) computed for every year. Three curated days were wrong and move: Eid al-Fitr 2025 is 1 April (not 31 March), Eid al-Adha 2025 is 6 June (not 7 June) and Eid al-Fitr 2026 is 20 March (not 21 March). Days the proclamations make working days are now OPEN (25 February 2025 and 2026; 21 August 2024, observed on 23 August), and days they add are closed (9 February 2024, 12 May 2025, 31 October 2025, 2 November 2026, every Christmas Eve). For 2027 onward, until each year’s proclamation is pinned, only the statutory fixed days are closed and the “Monday nearest” holidays are open: an opposition close on one of those days is published un-rolled, which is never later than the true date. The opposition extension note now cites IPOPHL Memorandum Circular 2022-013 itself: one 45-day extension, granted only once, on meritorious grounds, reckoned from the original due date, in force 30 June 2022. India (cgpdtm_india, new). Indian deadlines are now business-day adjusted. The Trade Marks Registry observes the annual DoPT Office Memorandum for central government offices; the 2024, 2025 and 2026 memoranda are pinned and their 14 compulsory holidays per year make up the calendar. in_renewal, in_restoration, in_opposition and in_opposition_madrid now report holiday_calendar: "cgpdtm_india" and moved / unchanged for 2024–2026 dates: a renewal due on Sunday 15 June 2025 is served as Monday 16 June; an opposition closing on Republic Day 2026 is served as 27 January. Dates after 2026 report not_checked until the 2027 memorandum is pinned. Three limits are documented, all in the safe direction: the three branch-local optional holidays (Mumbai, Delhi, Kolkata, Chennai and Ahmedabad differ), Ambedkar Jayanti, and any moon-sighting shift of an Islamic day are not modelled, so a deadline on one of them is published un-rolled. Iceland (is_iceland). No date changes. 24 and 31 December stay closed, now on the office’s own statement (Hugverkastofan’s December 2020 notice: closed on both days, deadlines falling on them move to the next opening day) and the statutes that make them half-day frídagar; 23 December stays open because the office declares it year by year. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. The materialised opposition_status and opposition_closes_before/opposition_closes_after search filters are baked at index time: IN and PH search documents carry the rolled and corrected closes only after those offices are reindexed. Maintenance rows are computed per request and need no reindex.

September 3, 2026: Korea (KIPO) deadline and opposition rules

New jurisdiction. KR now has a maintenance config and two opposition rules, so GET /v1/deadline-rules, GET /v1/opposition-rules, POST /v1/deadlines/compute, POST /v1/oppositions/compute (office KR) and the derived block on a trademark answer for Korean marks instead of returning nothing. Three new rule_id values: kr_renewal, kr_opposition, kr_opposition_madrid. Renewal runs 10 years from the REGISTRATION date (상표법 제83조①), with a 12-month filing window before the term ends that closes on the expiry day and a 6-month window after it at 330,000 KRW per class instead of 300,000 (제84조②, 제78조③). Korean law has no restoration of a missed renewal application and no declaration of use, so neither is emitted: that absence is the finding, not a gap. Opposition is 30 days from KIPO’s own 출원공고 for applications published on or after 22 July 2025 (법률 제20697호), and 2 MONTHS for publications before that day; an international registration designating Korea is opposed on the identical window, running from KIPO’s publication rather than the WIPO Gazette (제180조①). Every value cites the Act, the fee rules or the KIPO publication it comes from, with a verbatim quote and a pinned snapshot. Two things about dates deserve a direct statement. First, the 22 July 2025 change is the first opposition pivot that switches UNITS (calendar months before, a day count after), and the engine now resolves the era’s length with its unit; nothing moves for any other office. Second, Korean deadlines are business-day adjusted against the kipo_korea calendar, which this release corrects from primary sources: 1 May (노동절) is now a closed day in every year (상표법 제16조제4호 names it, and the shipped calendar had omitted it), with a Saturday/Sunday substitute from 2026; 17 July (제헌절) is closed from 11 May 2026, when the amended 관공서의 공휴일에 관한 규정 made every 국경일 a public holiday again; and 28 September 2026 is OPEN, because the regulation substitutes a 설날/추석 day only when it falls on a Sunday and 26 September 2026 is a Saturday. A KIPO deadline that lands on one of those days moves accordingly. Four limits are documented rather than hidden. The renewal window_opens is one day earlier than KIPO’s own count (KIPO opens the window the day AFTER expiry minus one year); it is never rolled and never a deadline. Election days and 임시공휴일 designated by government notice are not in the calendar until the notice is pinned, so a deadline landing on one is published un-rolled: earlier than the true date, never later. A renewal filed ON the expiry day is modelled as surcharge-free, which is how KIPO’s example reads. And a Madrid designation is computed only when its international registration date is known: the KIPO connector must carry the IRN, and its publication date for a designation must be KIPO’s own 출원공고일. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters are baked at index time, so KR search documents carry these values only after KR is reindexed; no KR records are indexed today, so that reindex belongs with the KIPO connector rather than with this change.

September 3, 2026: Türkiye dates now roll, pre-2018 renewal windows and the 2017 opposition straddle corrected

Computed dates change for TR (TÜRKPATENT), on both engines. Three of the limits documented when Türkiye landed on 2 September are closed. Business-day adjustment is now applied. A Turkish renewal due date, grace end or opposition close that falls on a Saturday, Sunday, one of the fixed holidays of Law 2429 (1 January, 23 April, 1 May, 19 May, 15 July, 30 August, 29 October) or a Ramazan or Kurban Bayramı day is served on the next working day, so holiday_calendar reads turkpatent_turkiye and the two adjustment fields read moved or unchanged for dates in 2024 to 2030 (not_checked outside that range, where the calendar is not curated). The bayram days come from Diyanet İşleri Başkanlığı’s official tables for each year; the arefe half days, the afternoon of 28 October and the Presidency’s ad-hoc administrative leave days are working days and never move a date. This rests on a documented convention rather than an office statement: no TÜRKPATENT source states how a last day on a non-working day is treated before the office, and the roll applies the rule the general procedural statutes give the courts (HMK 6100 m. 93/1, İYUK 2577 m. 8/2). Direction of the change: every affected date moves LATER, by one to five days (for example, a renewal due on 1 May 2026, a Friday holiday, is now served 4 May; an opposition closing on 27 May 2026, the first day of Kurban Bayramı, is now served 1 June). Renewal cycles whose anniversary fell before 10 January 2018 now show the request window the repealed KHK 556 m. 41/3 gave them: window_opens and due_date move to the last day of the anniversary’s month (up to 30 days later than before), while grace_expiry stays on the exact anniversary plus six months, because m. 41/5 anchors the lapse on the end of the term. Every such cycle is historical (visible with include_missed); no current deadline moves. Opposition windows for applications filed before 10 January 2017 but published on or after it now get the three months the KHK gave them (SMK geçici m. 1/1 concludes an application under the law in force on its filing date), one month later than before; the served citation follows. Windows for applications filed on or after that date are unchanged. POST /v1/oppositions/compute accepts an optional filing_date per item for this; omit it and the item falls back to the publication date, which yields the shorter modern window. This filing-date key applies to national applications (tr_opposition) only. Madrid designations (tr_opposition_madrid) stay keyed on the publication date: a designation’s filing_date is the international registration date, and a subsequent designation of Türkiye carries no date of its own, so a filing-keyed pivot would have served a subsequent designation made after 10 January 2017 on an older international registration three months instead of the two SMK m. 18/1 gives it, one month too late. An original designation on a pre-2017 international registration published on or after 10 January 2017 is therefore served two months where the KHK arguably gave it three; every such window closed in 2017. Trademark responses and POST /v1/deadlines/compute recompute per request, so they are correct as soon as this deploys. TR reindex required: the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters read window dates baked at index time, so Turkish search documents carry the rolled and filing-keyed close dates only after TR is reindexed.

September 3, 2026: Danish renewal dates on office closing days now roll

Computed dates change for DK (DKPTO). A Danish renewal due date or grace end that falls on a Saturday, Sunday, a Danish public holiday or one of DKPTO’s enumerated closing days is now served on the next working day, as the office’s own Varemærkehåndbog states (“Er sidste rettidige indbetalingsdato en dag, hvor Patent- og Varemærkestyrelsen ikke har åbnet … så er betaling førstkommende hverdag rettidig”) and as dkpto.dk/lukkedage confirms for the closing days (“På officielle lukkedage, vil alle frister automatisk blive forlænget til førstkommende hverdag”). Rows now read holiday_calendar: "dk_denmark" with moved or unchanged adjustments instead of not_checked. Direction of the change: dates move LATER only, by one to seven days (a mark registered 10 January 2017 was due 10 January 2027, a Sunday, and is now due 11 January; a renewal due 28 December 2026 rolls through the 28 to 30 December closure, New Year’s Eve, New Year’s Day and the weekend to 4 January 2027). Marks whose dates already fall on a working day do not move. Computed at request time; no reindex (maintenance deadlines are not indexed).

September 2, 2026: Philippines Renewal DAU window opens six months earlier

Computed dates change for PH (IPOPHL). The ph_declaration_of_use_renewal rule (the Declaration of Actual Use due within one year of each renewal) used to open its filing window at the renewal itself. IPOPHL’s Trademark Regulations of 2023 (Memorandum Circular 2023-001, in force 14 February 2023) say in Rule 206 that “The Renewal DAU may be filed within the six-month period before the expiration of the registration”, so the window now opens six months before expiry - together with the renewal window - for every renewal cycle expiring on or after 14 February 2023. Cycles that expired before that day keep the old window: the change is modelled as an era pivot inside the rule, keyed on the cycle, not on today’s date, and a window for a cycle expiring inside the first six months of the new regime opens on 14 February 2023 itself, because no filing could precede the Regulations that permit it. Only window_opens moves. due_date and grace_expiry are unchanged (one year after the renewal, no grace), and so is every other Philippine rule. The customer-visible effect is an earlier window_open status: a mark registered 5 January 2020 now shows its first Renewal DAU window opening 5 July 2029 instead of 5 January 2030. Under the 2017 Regulations (MC 17-010) Rule 206 was only a transitional trigger, which is why the earlier window is right for the earlier cycles; both texts are pinned with verbatim quotes, and the in-force date is pinned from WIPO Lex because the circular’s own Rule 1406 carries it handwritten. Maintenance deadlines are computed per request, so no reindex is involved.

September 2, 2026: Philippines Madrid designations get their own DAU anchors

Computed dates change for PH (IPOPHL) international registrations. Two new rule_id values, ph_declaration_of_use_3yr_madrid and ph_declaration_of_use_5yr_madrid, serve marks on the madrid route. Under IPOPHL’s Madrid Regulations (MC 17-011, Rule 20) the 3rd-year DAU of an international registration designating the Philippines runs “within three years from the date of the international registration” and the 5th-year DAU “within one (1) year from the fifth anniversary of the date of statement of grant of protection” - not from the national filing and registration dates the ph_declaration_of_use_3yr and ph_declaration_of_use_5yr rules use. Those two rules now apply to the national route only (applies_to: domestic); the Madrid rules read applies_to: madrid_only, trigger on intl_registration_date and protection_grant_date respectively, and are absent when the record does not carry that date rather than guessed from another one. A designation with no international registration date still returns no schedule at all (requires_office_date), as before. The Renewal DAU and Mid-Renewal DAU are unchanged for designations: Rule 20 runs them from the renewal of the registration, which for an international registration is the WIPO renewal on the international registration date the renewal row already uses. One limit is documented rather than hidden: a SUBSEQUENT designation’s 3rd-year DAU legally runs from the recording of that designation, and the engine anchors it on the international registration date instead, which is never later. No reindex is involved.

September 2, 2026: Swedish publication and expiry dates corrected (PRV connector)

Two corrections to how we read PRV’s bulk feed. Neither changes a stored record until the PRV backfill and reindex have run, so existing responses are unchanged at deploy time; the dates below move once that maintenance completes. publication_date for national registrations since December 2022. PRV’s feed dates the registration notice by gazette issue, one day (occasionally two or three) after the registration decision. PRV counts the opposition period from the kungörelsedag, which is the registration day itself, and its own register shows the opposition period starting on that day. We now take the registration day as publication_date for the registration notice; the gazette issue date stays on publications[].publication_date. After the backfill and reindex, publication_date on affected Swedish marks moves one day earlier (to registration_date), and every Swedish opposition window computed from it (derived.opposition_window, the opposition_status and opposition_closes_* filters) moves one day earlier at both ends. Together with the opening-day correction below, a mark registered on 1 April now shows a window of 1 April to 1 July, matching PRV, instead of 3 April to 2 July. Marks registered before December 2022 already carried the registration day and do not move. Madrid designations of Sweden are not touched by this change. expiry_date for registrations from 2019 on. PRV reports a ten-year expiry for every registration, but our far-future date guard (built for a handful of corrupt year-2077 and year-5014 owner dates) rejected any date more than two years out, so Swedish registrations from 2019 on, and older marks whose latest renewal runs past 2028, were served with no expiry_date and no renewal_due_date. Both are now ingested as reported. Renewal deadlines for these marks anchor on PRV’s own date once it is stored; where that differs from the statutory computation we used before, PRV’s date wins.

September 2, 2026: Canada (CIPO) opposition extension benchmark before December 2023

No computed date moves. window_opens, window_closes and status for Canadian marks are unchanged; this corrects the advisory common_extension field only, and only for the direct (non-Madrid) route. The Trademarks Opposition Board rewrote its “Practice in trademark opposition proceedings” on 1 December 2023 and cut the benchmark first extension to file a statement of opposition from 4 months (with a cooling-off extension of up to 9 months on consent) to 2 months (up to 7). The ca_opposition rule served the post-2023 figure for every window. The office’s own transition rule keys on when the extension request was received (“requests for extensions of time received on or after December 1 will be subject to the revised extensions of time”), and a non-retroactive s. 47(1) request is received no later than the deadline it extends, so the rule now keys on the served close date:
  • derived.opposition_window.common_extension for a CA direct-route window that closes before 1 December 2023 now reads months: 4 (was 2) with notes naming the 2019 notice and the 9-month cooling-off figure.
  • A window closing on or after 1 December 2023 keeps months: 2; its notes are rewritten (they no longer claim the window is “otherwise non-extendable” - the 7-month cooling-off extension exists) and name the straddle: a window that opened before 1 December 2023 and closes on or after it may have been extended under either figure depending on when the request was received.
  • GET /v1/opposition-rules continues to show the current (2-month) tier for ca_opposition; the rule’s citations gain the superseded 2019 notice and CIPO’s own side-by-side changes page, both pinned from the Wayback Machine because the office has removed them.
  • ca_opposition_madrid is untouched: Trademarks Regulations s. 125 caps the Protocol-application extension at 4 months in every era.
One documented limit: the 4-month figure is verified for the notice in force from 17 June 2019. The benchmark under the 2009 notice it replaced is not pinned, so a window closing before 17 June 2019 is served the 4-month figure with notes saying so. No search filter reads common_extension, so no reindex is needed.

September 2, 2026: MX oppositions before 30 August 2016 are no longer served

Computed dates change for MX (IMPI). Mexico had no pre-grant opposition procedure until the decree published in the Diario Oficial de la Federación on 1 June 2016, whose sole transitorio puts it in force “a los 90 días naturales siguientes a su publicación” - 1 June 2016 plus 90 calendar days, i.e. 30 August 2016. The same decree introduced the pre-grant publication of the application, so an MX record carrying a publication date before that day is showing a registration publication, which never opened an opposition period. The mx_opposition rule now declares applicable_from_date and effective_from of 2016-08-30, and MX publications earlier than that return no opposition window at all. Direction of the change: windows are REMOVED, never added. Nothing about a publication on or after 30 August 2016 moves - the one-month non-extendable period, its day-after start and its rollover calendar are unchanged. If you read an opposition window for an MX mark published before 30 August 2016, that window was wrong and is now absent. Trademark responses recompute the opposition window per request, so they are correct as soon as this deploys. The opposition_status and opposition_closes_before/opposition_closes_after search filters read values materialised at index time, so until the MX index is rebuilt those filters may still match Mexican marks published before 30 August 2016 even though the returned record now carries no opposition window.

September 2, 2026: India (CGPDTM) deadline and opposition rules

New jurisdiction. IN now has a maintenance config and two opposition rules, so GET /v1/deadline-rules, GET /v1/opposition-rules, POST /v1/deadlines/compute and the derived block on a trademark answer for Indian marks instead of returning nothing. Four new rule_id values: in_renewal, in_restoration, in_opposition, in_opposition_madrid. Renewal runs 10 years from the APPLICATION date, not the grant: s. 23(1) of the Trade Marks Act 1999 registers a mark “as of the date of the making of the said application”. The filing window opens a year before expiry (Rules 2017 r. 57(1)), a 6-month surcharge window follows expiry, and restoration is available after 6 and within 12 months from the expiry itself. Marks registered before the Act commenced on 15 September 2003 run 7-year periods until the first period that starts on or after that date. Opposition is 4 months from publication of the Trade Marks Journal issue that advertised the application, counted from the day after (General Clauses Act 1897 s. 9(1)) and non-extendable; it was 3 months for applications published before 8 July 2013. An international registration designating India is opposed on the same 4-month window, running from the INDIAN Journal republication rather than the WIPO Gazette. Every value cites the statute, the Rules or the CGPDTM practice document it comes from, with a verbatim quote and a pinned snapshot. Six limits are documented rather than hidden. No closed-day roll is applied to any Indian date: the law requires one but the Registry publishes no consolidated holiday list, so holiday_calendar is null and every adjustment reads not_checked rather than a guess. A mark claiming convention priority expires on its PRIORITY date plus ten years, which the engine cannot compute without an office-supplied expiry. A mark registered late may renew within six months of its actual registration, so its real due date can be later than the one published. A mark filed before 15 September 2003 but registered after it takes a ten-year first term, where the schedule gives seven. And nothing in the Act or Rules settles whether a renewal filed ON the expiry date avoids the surcharge; the conservative reading is modelled. Lastly, the anchor of the pre-2003 seven-year terms is not pinned to a quotable source: s. 159(6) evidences the seven-year length but not the date it runs from, and India Code’s scan of the 1958 Act carries no text layer to quote, so if the filing-date anchor is wrong the direction of the error is unknown. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters are baked at index time, so IN search documents carry these values only after IN is reindexed; no IN records are indexed today.

September 2, 2026: Türkiye (TÜRKPATENT) deadline and opposition rules

New jurisdiction. TR now has a maintenance config and two opposition rules, so GET /v1/deadline-rules, GET /v1/opposition-rules, POST /v1/deadlines/compute and the derived block on a trademark answer for Turkish marks instead of returning nothing. Three new rule_id values: tr_renewal, tr_opposition, tr_opposition_madrid. Renewal runs 10 years from the FILING date, with a 6-month filing window before the term ends and a 6-month window after it against an additional fee; missing both ends the right. Turkish law has no restoration and no declaration of use, so neither is emitted: that absence is the finding, not a gap. Opposition is 2 months from the publication of the APPLICATION in the Bülten, non-extendable, and identical for Madrid designations (SMK m. 14/1 makes an international application produce the same results as a direct one); publications before 2017-01-10 get the 3 months the repealed KHK 556 gave. Every value cites the statute or the TÜRKPATENT publication it comes from, with a verbatim quote and a pinned snapshot. Five limits are documented rather than hidden. No business-day adjustment is applied to any Turkish date: no Turkish source states that a deadline falling on a non-working day extends before the office, and TÜRKPATENT’s own 2025-03-29 notice told users to file during an administrative holiday, so holiday_calendar is null and both adjustments read not_checked on every row. Renewal cycles whose anniversary falls before 2018-01-10 were governed by a month-end-anchored request window that the engine does not yet express, so their window_opens and due_date can be up to 30 days early; every such cycle is in the past. (grace_expiry is not affected: the repealed KHK 556 anchored the six-month lapse on the exact end of the term, which is what we publish.) An application filed before 2017-01-10 but published after it legally had a 3-month opposition window while we publish 2: earlier than the true date, never later. Applications published in Marka Bülteni 410 to 417, roughly 12 December 2022 to 27 March 2023, carry opposition end dates that TÜRKPATENT’s 2023-04-14 notice fixed per bulletin once the periods suspended after the February 2023 earthquakes restarted; a one-off table is not a rule, so those office-fixed close dates are not modelled and the notice is pinned to keep the limit auditable. And whether a renewal request filed ON the day the term ends is still surcharge-free is stated by neither SMK m. 23/2 nor the office, so the exact anniversary is kept as the due date. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters are baked at index time, so TR search documents carry these values only after TR is reindexed; no TR records are indexed today, so that reindex belongs with the TÜRKPATENT connector rather than with this change.

September 2, 2026: Japan (JPO) deadline and opposition rules

New jurisdiction. JP now has a maintenance config and two opposition rules, so GET /v1/deadline-rules, GET /v1/opposition-rules, POST /v1/deadlines/compute and the derived block on a trademark answer for Japanese marks instead of returning nothing. Four new rule_id values: jp_renewal, jp_restoration, jp_opposition, jp_opposition_madrid. Renewal runs 10 years from the registration date, with a 6-month filing window before expiry and a 6-month late window after it; missing both extinguishes the registration retroactively, and a further 6-month restoration window follows. Opposition is POST-registration: 2 months from the day after the 商標掲載公報 issue, non-extendable, with the same window for Madrid designations. Deadlines falling on a JPO closed day roll to the next open day. Every value cites the statute or the JPO practice document it comes from, with a verbatim quote and a pinned snapshot. Three limits are documented rather than hidden: the published window_opens can be 1 to 3 days earlier than 商標法第20条第2項 allows, and grace_expiry can be up to 7 days early when the expiry lands on a closed day. Madrid designations are also served a jp_restoration row that Japanese law does not give them. All three are fixed by engine changes that ship separately. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters are baked at index time, so JP search documents carry these values only after JP is reindexed; no JP records are indexed today.

September 2, 2026: opposition window opening day corrected (Benelux, Finland, Norway, Sweden)

Opposition windows for BOIP, PRH Finland, Patentstyret, and PRV Sweden now open on the publication day, one day earlier than before. Their closing dates are unchanged. The served opposition rule_version moves to 2026-09-02. derived.ruleset_version on trademark responses (backed by the internal DEADLINE_RULESET_VERSION constant) also moves to 2026-09-02. It is one global stamp (the maximum lastVerified across all maintenance configs), so it moves for every record in every jurisdiction, including ones this release did not touch; this release bumped that maximum. The version move on its own does not imply that any computed date changed. REINDEX required for these four offices. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status filter stays stale until those offices are reindexed, because opposition_window_opens is baked into existing search documents; the opposition_closes_before/opposition_closes_after filters are unaffected, because no closing date moves. Benelux, Finland and Norway can be reindexed now. Sweden caveat. For marks registered since December 2022, the publication date we stored for PRV came from the gazette issue, which runs one day after the registration decision (40 of 40 records sampled per month). PRV counts the opposition window from the registration day itself. The connector correction is in the “Swedish publication and expiry dates corrected” entry above; Swedish opposition windows stay one day late until the PRV backfill and reindex described there have run. Sweden is reindexed after that backfill, not with the other three offices.

September 2, 2026: German renewal dates corrected for applications pending on 14 January 2019

DE national marks filed before 14 January 2019 but registered on or after that date now expire on the exact filing anniversary. They were previously shown with a month-end deadline, which is later than the law allows (for example, 2028-10-31 instead of 2028-10-05). Marks already registered before the cutoff retain month-end expiry, and office-reported expiry dates still take priority. The correction is computed at request time; no reindex is required. Scope of the change: only DE national marks filed before 2019-01-14, registered on or after that date, and without an office-reported expiry date. Our deadline evaluation harness holds no DPMA samples, so 0 records in it move. The first renewals for this group fall in 2028 and 2029, so no affected deadline is currently past due.

September 2, 2026: French renewal grace end corrected (moves later)

French renewal grace periods previously ended early, so customers had more time than Signa showed. They now run for six months from the day after the registration expires, matching CPI R. 712-24 and R. 718-2 exactly. Scope: no French renewal grace end moves earlier. Most move one day later. A grace period whose due date falls on a month end can move up to four days later, because the old and the new end clamp to different month ends: a due date of 2026-02-28 moves its grace end from 2026-08-28 to 2026-09-01, a due date of 2026-04-30 moves two days, and 2028-02-29 moves three. A few whose old and new ends both clamp to the same month end do not move at all. The correction is computed at request time, so no reindex is required (maintenance deadlines are not indexed).

September 2, 2026: office calendar corrections

Deadline rollover calendars now match the 2026 audit of official office closures. No rule window or anchor changed. Trademark responses recompute opposition windows per request, so every office below is correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters stay stale until the offices named below are reindexed.
  • EUIPO: 8 December 2025 and 2026 no longer roll; those are Article 2 ordinary-post-only days, not Article 1 office closures. Reindex EU opposition documents.
  • CIPO: weekend substitutes for 24 June and 30 September now roll on the following Monday. Those two need no reindex before the first affected 2028 opposition cohort. Separately, the 17–19 September 2025 office closure now rolls through the weekend to 22 September, so CA documents published 17 to 19 July 2025 carry an opposition close date up to five days early until CA is reindexed. Opposition status is unaffected: those windows are already closed.
  • IPOS: 11 August 2025 and 20 March 2026 no longer roll; the excluded days 1–16 May 2024 roll to 17 May, and 14 October 2025 rolls to 15 October. Reindex affected Singapore opposition documents.
  • IP Australia: Canberra Day, Saturday and Sunday ANZAC Day substitutes, and the standing 25 December–1 January close-down now roll. For example, 9 March 2026 rolls to 10 March, 27 April to 28 April, and 29 December to 4 January 2027. Reindex Australian opposition documents.
  • IPI: the conservative nationwide calendar now excludes canton-specific days, including 2 January, Good Friday, Easter Monday, Whit Monday, 1 May, 26 December. The governing party or representative canton is not available to the engine, so deadlines are never moved later based on the wrong canton. Reindex Swiss opposition documents.
  • DKPTO: 15 May and 28–30 December 2026 now roll as enumerated office closures. Reindex is not currently needed because Signa has no DK office documents; revisit when DK ingestion lands.
  • INPI France: 15 May 2026 now rolls to 18 May under the Director General’s closure decision. Reindex French opposition documents.
  • DPMA: the one-off Berlin holiday on 8 May 2025 now rolls to 9 May. No reindex is required for the weekly weekday publication cohort.

September 2, 2026: Era-aware opposition citations

The source on a computed opposition window now cites the instrument that states the window actually served. For rules whose opposition period changed on a fixed date, a publication before the change cites the earlier statute and a publication on or after it cites the amending law. This covers all seven opposition rules that change their period on a date, so a pre-change publication now cites the instrument that states the period it was given:
  • Australia, direct and Madrid, published before 2013-04-15 (3 months): Trade Marks Regulations 1995 reg 22.9 item 2 for a direct application and the 2012 compilation’s reg 17A.29(2)(b)(i) for an international registration, in place of the current reg 5.6(1) / reg 17A.33(1) “2 months”.
  • India, published before 2013-07-08 (3 months): Trade Marks Rules 2002 r. 47(1), in place of s. 21(1) “four months”.
  • Thailand, published before 2016-07-28 (90 days): s. 35 paragraph 1 of the Trademark Act B.E. 2534 as in force before Act (No. 3) B.E. 2559, in place of the current s. 35 paragraph 1 “sixty days”.
  • Türkiye, direct and Madrid, published before 2017-01-10 (3 months): the repealed Decree-Law 556 art. 35/1, and WIPO Information Notice No. 19/2014 for a designation, in place of SMK 6769 art. 18/1 “iki ay” for a direct application and the WIPO Madrid Member Profile (“two months from the date of publication of the international registration”) for a designation.
  • Vietnam, published before 2026-04-01 (5 months): Law 07/2022/QH15, in place of Law 131/2025/QH15, which states only the three-month period.
No window dates move, the source shape (citation, url) is unchanged, and no reindex is required: the citation is computed at request time.

September 2, 2026: Vietnamese opposition windows corrected (3 months since 1 April 2026)

Vietnamese trademark applications published on or after 2026-04-01 now have a 3-month opposition window. These windows were previously shown 2 months too late. Trademark responses recompute opposition windows per request, so they are correct as soon as this deploys. Only the materialised opposition_status and opposition_closes_before/opposition_closes_after search filters stay stale until VN documents published on or after 2026-04-01 are reindexed.

September 2, 2026: Brazilian and Mexican renewal deadlines

Renewal deadlines are now computed for Brazilian and Mexican registrations where none were computed before; the grant-date trigger was never fed from stored data. The affected cohort is BR and MX national-route registrations whose stored registration date feeds that trigger; records carrying an international registration number are excluded. The deadlines are computed at request time, so no reindex is required (maintenance deadlines are not indexed).

September 2, 2026: Icelandic renewal dates corrected

IS renewal deadlines: applications filed before 2020-09-01 are now anchored on the registration date for every renewal, even when registration occurred after the reform. They were previously shown early from the filing-date anniversary. For every affected record that carries a registration date the renewal moves later; none moves earlier. Records with an office-reported expiry remain anchored on that expiry. There is a third outcome. A pre-2020 IS record that carries neither a registration date nor an office-reported expiry now returns no computed renewal at all, where it previously returned one anchored on the filing date. The filing date is the wrong anchor for that cohort, so the deadline is withheld rather than guessed; send the registration date, or the office’s expiry date, to get a schedule back. This matches how the other registration-anchored pivots (SE, FI and NO) already behave. Denmark is not in that set: its pivot is keyed on the registration date rather than the filing date, so a DK record with no registration date falls through to the modern filing anchor and is served a schedule. Renewal deadlines are computed at request time, so no reindex is required. IS opposition dates did not change either: opposition_window_opens, opposition_window_closes and opposition_rule_version in the search index are unaffected. The index stores no rule citations at all. GET /v1/deadline-rules and GET /v1/opposition-rules serve sources[] straight from the deployed configuration, so the new IS primary-source citations take effect with the deploy (within the 24-hour reference-cache window), and no reindex is involved.

September 2, 2026: Office rule reference data provenance

Reference data: deadline and opposition rules for AU, BR, BX, CA, CH, DE, DK, EU, FI, FR, GB, MX, NO, PH, PL, SG, TH, US and WIPO now cite primary sources with verbatim quotes and pinned snapshots. sources[] on GET /v1/deadline-rules and GET /v1/opposition-rules changed for those offices: law-firm guides, publisher summaries and mirrors of primary text were replaced by the statute, regulation or office publication they paraphrased. Nothing else in those responses moved, and no computed date changed from the re-citation alone. IN, JP and TR are new rule sets rather than re-citations, and are announced separately above. For DE (DPMA) the opposition rule’s five bare links to individual gesetze-im-internet section pages are replaced by eleven pinned citations: MarkenG §§ 41, 42 and 91, MarkenV § 27, BGB §§ 187, 188 and 193, DPMAV § 18a, PatKostG § 6(1) with the opposition fee numbers, and the DPMA’s own opposition guideline W 7736 (Markenblatt publication, the Ereignisfrist arithmetic, and the rule that statutory periods cannot be extended). The German renewal config additionally cites PatKostG §§ 3, 5 and 7, BGB §§ 187 and 188, and three DPMA practice pages carrying the worked renewal example. No computed dates changed. For FI (PRH) both configs move to primary Finnish law. The renewal config’s two remaining links (an English PRH page and a law-firm alert) are replaced by twelve citations: Tavaramerkkilaki 544/2019 §§ 16, 30, 106 and 107 (the ten years from the application date, the one-year/six-month window, removal from the register, and the 1 May 2019 commencement that pivots the anchor), the repealed 7/1964 §§ 22 and 24 for marks applied for before it, the 1930 Act on calculating time limits for the same-numbered-day arithmetic, and three Finnish PRH pages. The opposition rule’s own statutory links are re-pinned (544/2019 § 32 and the 1930 Act) and joined by 544/2019 §§ 24 and 33, 7/1964 § 20 and four PRH pages. A citation to a Government Decree on Trademarks (1268/2018) was removed: that statute number belongs to an unrelated act and no decree governs the Finnish opposition period. No computed dates changed. For FR (INPI) the opposition rule loses all four of its previous links and gains thirteen pinned citations. Two of the four were wrong as well as unverifiable: the Légifrance article id cited for CPI art. L. 712-4 does not exist, and the one cited for Code de procédure civile arts. 641/642 identifies neither article (they are LEGIARTI000006411002 and LEGIARTI000006411003). The rule now cites CPI arts. L. 712-4 (both the in-force text and the pre-2019 text, with L. 712-3, showing the two months have not changed since 1992), R. 712-8 for the BOPI publication that starts the period, R. 718-2 for the same-numbered-day arithmetic and the weekend/holiday roll, R. 712-14 for the one further month allowed for the exposé des moyens, R. 712-15 for the inadmissibility of a late opposition and R. 712-12 for the absence of any restoration of it, plus INPI’s opposition directives (July 2026) and its current opposition page. The renewal config additionally cites CPI arts. L. 712-1 and L. 714-5 and INPI’s nullity/revocation page. Statutory text is quoted from the DILA open-data LEGI publication of each article version, because legifrance.gouv.fr blocks automated retrieval. No computed dates changed. For MX (IMPI) both configs move to primary Mexican law. The renewal config’s five previous citations - a WIPO Lex catalogue page and three law-firm guides, plus WIPO Information Notice 13/2018 - become thirteen: LFPPI arts. 178, 21, 233, 237 and 238 and transitorios PRIMERO, DECIMO and DECIMO PRIMERO (the ten years from grant, the six-month renewal window and six-month grace, the declaration of use in the three months after the third year, and the 2018-08-10 and 2020-11-05 commencements), the abrogated Ley de la Propiedad Industrial art. 95 for marks applied for before 5 November 2020, IMPI’s own LFPPI seminar deck, and Information Notice 13/2018 promoted in place with its quote. The opposition rule’s three links are replaced by seven citations: LFPPI arts. 221, 21 and 18, Reglamento de la LPI arts. 4o and 59 TER, the abrogated LPI art. 120 showing the one-month non-extendable period has not changed since 2016, and the transitorio Único of the decree published in the DOF on 1 June 2016, which is the text that dates the 2016-08-30 gate. All three were unusable: every one of them pointed at diputados.gob.mx, which no longer answers, and the Federal Code of Civil Procedure art. 286 is not the instrument that governs IMPI time limits either. Statutory text is quoted from the ordenjuridico.gob.mx consolidated PDFs. No computed dates changed.

September 2, 2026: The events feed is documented (beta)

GET /v1/events and GET /v1/events/{id} are now part of the published API reference and the OpenAPI document, under Monitoring. They were already live and callable with the events:read scope; what changed is that they are documented and supported rather than undocumented. The feed is your organization’s append-only event ledger, retained 30 days. Every webhook you receive is also a row in it, addressable by the same id (the webhook-id header IS the evt_* id), which makes it the recovery path for an outage your webhook retries could not cover: persist the last id you processed, then ask for ?sort=id&after=evt_…. A checkpoint older than the window returns 410 replay_window_expired; see Replay from a checkpoint. Beta means one specific thing here. The ledger, the evt_* ids, the filters and the replay rail are stable enough to build on. The per-event data payloads are versioned by payload_version and their shape is not yet promised. Pin payload_version in your consumer and read this changelog before upgrading. No behaviour changed: same rows, same filters, same scopes. The MCP surface adds a matching read tool, signa_events_list.

September 2, 2026: Alert diffs use public field names (breaking, beta)

data.alert.event.diff[].path on alert.created webhooks and GET /v1/alerts* now uses public trademark field names, the same ones trademark.status_changed adopted. Effective on deploy; alerts are in beta and this is the last chance to fix the vocabulary before it is frozen. Fields Signa tracks but does not publish (is_primary_source, mark_feature_type_raw, mark_legal_category_raw, application_language) are dropped rather than renamed, so a diff can be shorter than before, and every path you now see is a field you can read back from GET /v1/trademarks/{id}. event.summary is built from the same names, so the headline reads "Status changed: pending → registered" where it used to read "Status primary changed: …". Redeliveries (POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver) and automatic retry attempts of alerts created BEFORE this change are re-emitted with the new names too (event.summary included, since the headline is re-derived from the translated diff), so your handler only ever has to understand one vocabulary. GET /v1/events/{id} applies the same projection to the stored alert.created body, so the pull rail and a redelivered push of the same event agree. Nothing about which alerts fire, or when, changed.

September 2, 2026: Office dates and your docket reference on events

Three additive fields on trademark.status_changed and office_action.issued, on both the webhook body and GET /v1/events/{id}. Nothing was renamed, no stored value changed, and payload_version stays 1. source_date is the office’s date; occurred_at was always ours. occurred_at is when Signa produced the event: ingestion time for trademark.* and office_action.*, alert-creation time for alert.created. That was already true, and it is now documented per family instead of implied. The new source_date is the office-reported data date of the change as we stored it (YYYY-MM-DD, or null when the feed reports none), equal to event_date on office actions. The two differ by the office publication lag, typically 1 to 14 days, so sort a docket by source_date (meaningful within one office) and use occurred_at to answer “when did I learn this”. Its meaning is honest rather than uniform: day precision, USPTO transaction date, WIPO gazette date, snapshot offices the crawl date. It is not a legal effective date; changes.status_effective_date is. We deliberately do not fold the effective date into source_date, because an office re-crawl can backdate it by years and your feed would travel backwards on a mark that was merely re-read. portfolios carries your external_ref, frozen at record time. Both families now include the portfolios the mark was in when the event was recorded, each with the reference you set on the membership:
It is a snapshot, not a live lookup. Re-keying a matter reference tomorrow never rewrites an event you already received, which is what keeps a redelivery byte-identical to the original and keeps GET /v1/events/{id} in agreement with the body you verified the signature over. Empty array when the mark was in no portfolio; null external_ref means unknown or unset, never “cleared”. alert.created does not carry either field. The SDK adds EventPortfolioRef and the new fields on TrademarkStatusChangedData, OfficeActionIssuedData and the org-event detail types.

September 2, 2026: Webhook subscriptions, portfolio scope, and diff field names

Three contract clarifications on the event surface, all landing together. Subscribing no longer depends on our rollout state. enabled_events accepts alert.created, trademark.status_changed and office_action.issued at all times. The last two are accepted for subscription but not yet emitted: they begin delivering when the API events projector is enabled. Previously the accepted set widened with our rollout, which meant the published OpenAPI document described a different API depending on the environment you generated your client against. Subscribe now and you receive them from the first delivery. portfolio_id means one thing. An endpoint’s portfolio_id, and GET /v1/events?portfolio_id=, now filter every event type against the portfolio membership recorded when the event was recorded, alert.created included. Previously alerts bypassed the filter entirely, so a portfolio-scoped endpoint or query returned every alert in the organization regardless of portfolio. If you scoped an endpoint to a portfolio and relied on it still receiving all alerts, clear portfolio_id on that endpoint (or add a second, unscoped endpoint): similarity, class and owner watches match marks you do not own, and those alerts have no portfolio membership. changed_fields and changes use public field names. The trademark.status_changed payload and GET /v1/events/{id} now key the diff by the field names on the trademark resource instead of our internal column names: status_primary becomes status, mark_text_primary becomes mark_text, publication_date_first becomes publication_date, international_registration_number becomes ir_number, challenge_states becomes status_challenges, and changed child collections read as owners, classifications, media and so on. Internal-only columns are omitted rather than renamed, so both lists can be shorter than before. Every name you now see is a field you can read back from GET /v1/trademarks/{id}.

September 2, 2026: Richer goods/services validation evidence

POST /v1/goods-services/validate now adds descriptive wording coverage, candidate spans and USPTO template drafting aids, suggested class inference, cited indefinite-wording warnings, catalog as_of freshness, and explicit candidate-search completeness. Summary fields roll up inferred items, warnings, and complete, truncated, or degraded searches. listed and not_listed keep their existing catalog-membership meaning. The TypeScript SDK exposes the new types in version 0.12.0; version 0.11.0 was never published, so no published SDK contract is broken.

September 2, 2026: Goods/services catalog validation

POST /v1/goods-services/validate checks submitted wording against the pre-approved catalogs available for US, EM, JP, KR, and CN. listed means the wording appears in that office’s catalog. not_listed is an absence of evidence, not a refusal. Other recognized offices return unsupported_office with reason no_catalog_data. The endpoint returns one result per input item, bills per item, and can provide same-class candidate wording when class_number is supplied. An optional Idempotency-Key enables safe replay. The TypeScript SDK exposes it as goodsServices.validate() in version 0.11.0.

September 2, 2026: Entity lists and suggest answer 503 when OpenSearch is unavailable

GET /v1/owners, /v1/attorneys, /v1/firms, /v1/entities, /v1/suggest and /v1/trademarks/suggest no longer fall back to a degraded Postgres page or an empty result when OpenSearch is unavailable. They answer 503 service_unavailable with a Retry-After header instead. The SDK retries 503 automatically. Cursors and result ordering are unchanged on the happy path.

September 2, 2026: Saved searches removed

The /v1/saved-searches endpoints are gone and now answer 404. The signa.savedSearches SDK resource, the SavedSearch types, the from_saved_search option on signa.watches.create and the ssr_ id prefix were removed with them. The feature had no production usage. Store the search body on your side and re-send it to POST /v1/trademarks, or create a watch with the same query.

September 2, 2026: Swedish renewal dates corrected

SE renewal deadlines: registrations applied for before 2019-01-01 are now anchored on the registration date per the transitional rule (SFS 2018:1652 p. 4 a), whenever they were registered. About 1,300 active marks change date, in both directions: roughly 1,290 move later (they were shown up to 6 years early), and 8 move earlier or gain a deadline that was previously outside the horizon (their filing-anchored cycle had already elapsed; the registration-anchored one lands sooner, by up to 2,445 days). Computed at request time, no reindex. Records with an office-reported expiry are unaffected.

September 1, 2026: Office-action webhook events

office_action.issued is now a subscribable, versioned semantic event. It fires once for each newly stored office action on a portfolio mark and carries the stored prosecution-history fields using public office-code vocabulary. Emission begins when the API events projector is enabled. A first detail fetch that newly inserts multiple office actions stores them without webhook emission. A single-action history may emit one office_action.issued: one action is indistinguishable from a genuinely new one, and a stale event is safer than silently dropping a real refusal notice. Once history is known, each later new action emits once.

September 1, 2026: Trademark status webhooks and portfolio-scoped endpoints

trademark.status_changed is now available as a subscribable webhook event type. It carries the spine-native event envelope; emission begins when the API events projector is enabled. Endpoints without a portfolio_id receive every trademark.status_changed event for the organization; setting a portfolio_id narrows those deliveries to marks in that portfolio. POST /v1/webhooks, PATCH /v1/webhooks/{id}, and GET /v1/webhooks now expose the additive portfolio_id field.

September 1, 2026: Webhook event envelope (BREAKING)

This is a breaking webhook contract change. For alert.created, the envelope id and signed webhook-id header now use the spine event identifier (evt_*) instead of the alert identifier (alt_*). The payload is no longer a flat merged field bag: data is now { event_id, alert_id, alert }, with the rich alert resource nested under data.alert. webhook-id is the documented idempotency key. Migrate or reset stored idempotency keys during this upgrade so the alt_* to evt_* identity change does not cause incorrect duplicate handling. Update consumers to read paths such as data.alert.id and data.alert.event.type.

September 1, 2026: Forward replay on GET /v1/events

The event feed gains a second rail. The default feed keeps its shape and its rows: newest first, opaque cursor, same order (list items do gain two timestamp fields, detailed below). What is new is a forward rail a sync client can resume from, plus two behaviour changes on the existing surface that you need to know about before you upgrade. Discard any GET /v1/events cursor you have stored. Event cursors are now bound to the query that minted them. The payload carries the sort direction and a fingerprint of the filters, the limit and the sort, so a cursor can only be replayed against the identical query. Every cursor minted before this change lacks both, and now returns 400 cursor_invalid. Cursors were always documented as opaque and short-lived, so this only affects you if you persisted one. Restart from page one without a cursor. cursor_invalid is a different failure from cursor_expired, and the split is deliberate. cursor_expired means the value is not a cursor: malformed, unsigned, or minted for another endpoint. Restart from page one. cursor_invalid means the cursor is genuinely ours but is bound to a different query than the one you just sent, usually because a filter or the limit changed mid-pagination. Restart from page one with the parameters you actually want. since now filters on when Signa recorded the event, not when the office reported it. It used to bind the row’s creation timestamp; it now binds recorded_at, Signa’s ledger clock. This is what a sync client wants. Source timestamps can be backdated by an office arbitrarily far, so filtering on them silently skips late-arriving rows that were recorded after your last poll. Every event now carries both clocks explicitly, occurred_at for the office and recorded_at for us, so nothing is lost. created_at stays as an alias of recorded_at. sort=id turns the feed into a replay rail. Pair it with after=<evt_ id> to resume from a checkpoint you persisted, exclusive of the checkpoint itself. Ledger sequence is the only sortable field, and after is valid only with sort=id. sort=-id remains the default; its ordering and cursor behaviour are unchanged. List items gain occurred_at and recorded_at, and trademark_id is now nullable.
A checkpoint older than the retained window is a 410, not a silent gap. Replay is bounded by retention. If the events after your checkpoint have been pruned, the response is 410 replay_window_expired rather than a 200 that quietly omits them. The floor is per organization, so another tenant’s retention never affects your answer. Recovery is to start a new initial sync with sort=id and no after, then persist the newest event ID you see. The TypeScript SDK maps 410 to a new GoneError. portfolio_id is family-aware. It filters every event type through the portfolio membership snapshot captured when the event is recorded, so later membership changes never rewrite history. That includes alert.created: an alert is in a portfolio’s feed only when the alerting mark was in the portfolio at the moment the alert was recorded, and similarity, class and owner watches routinely match marks you do not own, which have no membership. This is identical to portfolio-scoped webhook delivery. The parameter requires portfolios:manage in addition to events:read.

September 1, 2026: Examiner citations

Three new endpoints, a new count on the trademark detail, and a per-office capability flag. Everything here is additive. The only thing that changes for an existing integration is that detail ETags rotate once, at deploy. Citations are now a first-class resource. A citation is a prior mark an examiner cited against a pending application. GET /v1/citations queries them across marks, filterable by offices, disposition, action_stage, refusal_type, trademark_id, cited_trademark_id, cited_ref and an action_date range. Each row is one citation occurrence: one prior mark, one application, one office action. And per mark, in both directions. GET /v1/trademarks/{id}/citations returns what was cited against that application. GET /v1/trademarks/{id}/cited-by returns the applications that mark has been cited against, which is the question a portfolio owner actually asks. cited-by also picks up citations matched by office-printed reference where Signa has not linked the row to a record yet, and the ?cited_trademark_id= filter on GET /v1/citations matches the same rows, so the two views agree. citations_count on the trademark detail. GET /v1/trademarks/{id} and POST /v1/trademarks/batch carry a new citations_count. It is present on every full-detail response, including the batch lookup surface, and it is nullable. Like events_count and proceedings_count, it is dropped by a sparse ?fields= projection that does not ask for it. An integer, including 0, means the office is covered and that is the real count. null means citations are not counted for that office at all, which is not the same as “there are none”. capabilities.citations tells you which is which. GET /v1/offices and GET /v1/offices/{code} now carry a capabilities block whose citations field reads available, in_progress, not_available or not_applicable. available offices return a number in citations_count; every other state returns null. not_applicable is the useful one: an office that does no ex-officio relative-grounds examination never issues a citation-bearing refusal, so its empty list is a fact about the regime rather than a gap in our coverage. Branch on this field instead of inferring coverage from an empty response. Coverage today is USPTO §2(d) refusals. SDK. signa.citations.list(), signa.trademarks.citations(id) and signa.trademarks.citedBy(id), all auto-paginating like every other list. Detail ETags rotate once. The representation salt goes from v3 to v4, so the validator format is now "v4.{version}-{epoch}" plus the derived content hash, plus a citations_count hash on covered offices. Every cached trademark detail body misses once and refetches. Nothing to change on your side. The extra hash exists because citations are written by the extraction pipeline, which does not touch the record’s version: without it, a client holding an ETag would be revalidated onto a stale count forever.

September 1, 2026: Every rule has a stable id

Deadline and opposition rules now carry a permanent rule_id, so a computed date can be traced to the rule that produced it and joined to the catalogue that documents it. rule_id is an opaque slug (do not parse it), and it will not be renamed once published. Alongside it, two dates that were previously conflated are now separate. effective_from is the earliest date from which a rule’s modelled content is authoritative, and is null where the corpus does not establish one. last_verified is when we last checked the rule against its sources; on opposition rules that is the value rule_version has always carried. POST /v1/deadlines/compute rows gain rule_id, effective_from, last_verified and the business-day provenance due_date_adjustment, grace_expiry_adjustment and holiday_calendar. The two adjustment fields are moved, unchanged or not_checked. not_checked covers a jurisdiction that does not observe the roll, an office with no wired calendar, and a date beyond a calendar’s coverage, so a date we never checked is never reported as one we checked and left alone. Each item also carries the jurisdiction’s sources, plus as_of and computed_at, which together make a response replayable as a record of what was computed and when. POST /v1/oppositions/compute gains rule_id and effective_from; rule_version is unchanged. Both catalogues expose the same three fields, and GET /v1/deadline-rules now also serves the restoration rules for Great Britain, Singapore and Iceland, which the engine could always compute but the catalogue never listed. Trademark detail, portfolio deadlines and watch diagnostics carry rule_id on each row. All fields are additive. One caching note: the trademark detail response folds a content hash of its derived block into the ETag, and that block now carries rule_id, so detail validators rotate once on this release.

September 1, 2026: Prosecution deadlines on /v1/deadlines/compute

POST /v1/deadlines/compute now computes prosecution deadlines as well as maintenance ones: office action response periods and statement of use clocks, resolved per fact instance. Send an optional facts array on any item and the result gains prosecution_deadlines[] and support[]. This is additive. prosecution_deadlines[] and support[] appear only on items that sent facts. (The same release adds rule identity to every item (see the entry above), so an item you send without facts is unchanged apart from those provenance fields.) Every computed date cites its rule. Each prosecution deadline carries the rule id, the era it belongs to (effective_from / effective_until), which case date selected that era, when the rule was last verified against source, and the sources themselves with pinpoint section, verbatim quoted text and a sha256 of the snapshotted document. A computed date that cannot cite its rule does not ship. Support is now per deadline type, and it is honest about coverage. A single supported: boolean could not say that a US mark has a renewal schedule but no office action deadline, so support[] reports one entry per type with a four-valued status:
  • computed, a modelled rule produced or retired a date
  • stated, no modelled rule exists but the office stated the deadline itself
  • facts_required, a rule exists and is verified, but you must supply the trigger
  • unsupported, no rule is modelled
Today that reads: USPTO computes from stored or supplied events. EUIPO rules are verified but Signa stores no EUIPO examination events, so EUIPO is facts_required until you send the trigger. There is no Madrid level rule and there will not be one, because the Madrid System does not set the holder response period; it is designated office law. For an unmodelled contracting party, send a stated_deadline fact carrying what the office declared and the date comes back with the notification as its authority. The item level unsupported_reason enum widens from 2 values to 20 so both engines share one reason vocabulary. The field itself still only emits the two maintenance values; the new codes appear on support[].reason and prosecution_deadlines[].reason. Treat it as an open enum. Billing is unchanged: 1 unit per item, whether or not the item carries facts.

August 31, 2026: Computed data moves under derived

A response-shape change on the trademark detail and batch endpoints, plus a new provenance field. This is a breaking change: deadlines[] and opposition_window move, and three fields on each deadline row go away. We are shipping it during beta, before anyone has built on the old shape. Everything Signa computes now lives under derived. deadlines[] becomes derived.deadlines[] and opposition_window becomes derived.opposition_window. The split makes the boundary visible. Fields at the top level are what the office told us. derived is what we computed. Nothing about what we compute has changed, only where it sits. Deadline rows now carry dates, not countdowns. status, urgency and days_until_due are gone from the trademark response. Each row instead carries window_opens, due_date and grace_expiry, plus new trigger_date, trigger_field, recurring and optional fields. The reason is caching. Those three fields were functions of the day you read the response, but the response is cached and revalidated against a record-versioned ETag. A client that held an ETag and revalidated a week later got a 304 and kept serving last week’s countdown, indefinitely. A value that changes without the record changing cannot live in a cacheable body. Deriving them is a couple of lines against your own clock:
If you would rather the server do it, POST /v1/deadlines/compute takes an explicit as_of_date and still returns status, urgency and days_until_due. Its clock is an input, so it caches correctly. GET /v1/portfolios/{id}/deadlines is unchanged. Opposition windows lost their clock fields too. derived.opposition_window drops status, days_until_open and days_remaining, and adds rule_version. On search and list rows, opposition_window keeps window_opens and window_closes and drops status. The opposition_status filter is unaffected. The server still evaluates it, so filtering by open or not_started works exactly as before. An empty schedule now says why it is empty. [] used to be ambiguous between “this mark has no deadlines” and “we declined to compute one”. derived.deadlines_supported is now false with a derived.deadlines_unsupported_reason of either unsupported_jurisdiction or requires_office_date, the same vocabulary POST /v1/deadlines/compute already returns. derived.ruleset_version stamps the rule state that produced the block. renewal_due_date now declares where it came from. It sits at the top level next to office-reported dates, but it is office-stated for some records and computed by the connector for others, and nothing said which. The new renewal_due_date_basis reads reported, derived or unknown, exactly like expiry_date_basis. Connectors adopt it one at a time, so expect unknown on records whose connector has not declared one yet. Detail ETags all rotate. As of this release the validator format is "v3.{version}-{epoch}" with a content hash of the derived block appended, so cached copies of the old shape miss and refetch. Nothing to do on your side beyond expecting one full response per cached mark. (The v3 salt moved to v4 in the September 1 release below.)

August 30, 2026: Deadline engine statutory corrections

A correctness pass over the maintenance deadline engine. This is a behavior change: the same trademark can now return a different status, a different number of deadlines[] rows, and different dates on four jurisdictions. Read this before upgrading if you drive filing workflows off computed deadlines. The due day and the last grace day are now actionable, not missed. Status boundaries are inclusive on the actionable side. On the due date a deadline reads due_soon, not missed. On the last day of the grace period it reads in_grace, not missed. missed now begins the day after grace expiry (or the day after the due date where a rule has no grace period, such as the Mexican third-year declaration of use). If you filtered for missed to build a “too late to file” list, that list previously included two days you could still file on. Refused applications no longer return a maintenance schedule. A refused application has nothing to maintain, so deadlines[] is now [] for it. The one exception is Madrid-route records: a provisional refusal from a designated office is routinely overcome, so Madrid-route marks keep computing their schedule. Expired and cancelled marks now return their still-actionable rows instead of an empty array. These statuses are recoverable for a bounded window, and returning [] hid exactly the deadlines a customer needs at that moment. An expired mark now returns its open late-renewal window (the current cycle while its filing window or grace period is open) plus its restoration row where the jurisdiction provides one (GB, SG, IS). A cancelled mark returns its restoration row only, where modeled. Statuses that are terminally dead (abandoned, withdrawn, surrendered, invalidated, and refused, except the WIPO international registration record itself under a provisional refusal) still return [].
  • This can add rows to marks you already fetch. A cancelled GB mark that returned no deadlines yesterday can return a restoration row today. Client code that assumed a dead mark implies an empty array should be checked.
  • Rows can also disappear for expired marks without a reported expiry. The engine will not invent a lapse it cannot corroborate: an expired mark with no office-stated expiry date is served only the cycle whose window is currently open, never a restoration row derived from an assumed earlier miss. Clients alerting on deadlines[] shrinking should expect this.
Restoration rows are no longer flagged optional. Restoration is the only way back onto the register once removal is final, so optional is now false on those rows, and include_optional=false no longer suppresses them. If you pass include_optional=false on POST /v1/deadlines/compute to trim the response, expect restoration rows to appear where they did not before. Four statutory anchors were corrected. These change computed dates, not just labels.
  • Denmark: the 2019 regime split is keyed on the registration date, not the filing date (Lov 1533/2018 §8 stk. 3). Marks filed before 2019-01-01 but registered after it were anchored up to a year off.
  • Mexico: the 2020 regime split is keyed on the filing date, not the grant date (LFPPI Transitorio DÉCIMO). Applications in prosecution when the LFPPI entered into force on 2020-11-05 stay on the old filing-anchored term.
  • Philippines: the third-year declaration of use window opens at the filing date and runs to the third anniversary of filing (RA 8293 §124.2). It was previously computed as a single day.
  • Thailand: publications before 2016-07-28 get the 90-day opposition window that was in force at the time. The 60-day window applies only from the 2016 amendment forward.

July 25, 2026: Jurisdiction protection scope

A precision fix to what jurisdictions means, plus honest screening verdicts when register coverage is incomplete. This is a behavior change: the same request can now return more results and, for screening, a new verdict value. Because it changes result sets during beta, read this before upgrading. jurisdictions now selects rights that protect, or seek protection, in a territory, not just literal territory legs. Previously jurisdictions=FR matched only French national filings and Madrid designations of France. It now also matches regional rights whose membership covers France, so a EU trade mark (which protects France) is included. See Search Trademarks and the glossary.
  • Result counts grow. A country-scoped filter picks up the regional rights that protect it. On production data, jurisdictions=FR roughly doubles once EU trade marks are counted. Countries with no live national office but active EU coverage (for example DE) go from a handful of Madrid hits to full EUTM coverage.
  • territory_match=direct restores the old behavior. Pass it to match only literal territory legs, byte-for-byte the pre-July-2026 result set. The default is territory_match=protection. Requesting a regional code (EU) stays strict on search: it matches EUTMs and IRs designating the EUIPO, not member-state national marks.
  • Why results grew is now explained. Under the default protection mode, each hit returned with a jurisdictions filter carries territory_matches[], mapping the requested code to the territory it matched on and the basis (direct leg or regional_membership). The field is absent under territory_match=direct. search_meta.territory_match echoes the mode that ran.
  • Suggest and image search grow too. GET /v1/trademarks/suggest and POST /v1/trademarks/search/image apply the same protection-scope expansion and accept territory_match. Suggest now also matches Madrid designations of a requested territory (an international registration designating France is suggested under jurisdictions=FR), and image search echoes the applied mode as search_meta.territory_match.
  • Member-country codes are newly accepted. Benelux member states (BE, LU, NL) and OAPI member states (for example SN) had no jurisdiction row of their own and previously returned 400. They are now valid jurisdictions values, so jurisdictions=BE selects Benelux and EU rights that protect Belgium.
  • Saved searches were removed on September 2, 2026. Saved searches replay under the new semantics automatically. A stored search with jurisdictions=FR is re-executed against the current matcher, so it now returns EU trade marks it did not before, with no change on your side. If you need a saved search to keep the old literal-leg behavior, re-save it with territory_match=direct.
  • Breaking for pagination. Because the query shape of a jurisdiction-filtered search changed, pagination cursors minted before this release on such a query now return 400 cursor_invalid. Clients holding a stale cursor must restart pagination from the first page.
  • During the rolling deploy, expect a brief mixed window. While the release rolls out, requests may land on either old or new instances, so a jurisdiction-filtered query can alternate between the old and new result sets, and territory_match may return 400 from a not-yet-updated instance. Stale jurisdiction-filtered cursors invalidate as above. The window closes once every instance is on the new release; retry the request if you hit it.
Screening can now return needs_review when register coverage is incomplete. A clearance verdict is only trustworthy if Signa can actually see the marks that protect a requested territory. When the register that would carry a conflict is not connected live, a zero-conflict screen must not read as clear.
  • New verdict value. GET /v1/screening verdicts are now high_risk / caution / needs_review / clear. needs_review is a would-be clear that could not be confirmed because a requested territory’s register is dark or stale. Handle it as “we could not rule this out”, not as a weaker clear. Found conflicts still band high or medium exactly as before, observed risk is never suppressed.
  • Why this is deliberate. Before this change, screening a common brand in a class scoped to a territory whose national register was not yet connected could return clear with zero conflicts, even though real national marks existed and were simply invisible to us. Returning clear there is a false negative on a clearance product. We would rather tell you the corpus was incomplete than imply a name is safe.
  • A new coverage block on the screening response reports which registers gated the verdict (offices axis in ST.3 codes, territories axis in jurisdiction codes) and a complete_for_clear boolean. See Screen a Name.
  • Check a Listing gets the same protection-scope expansion, and an incomplete requested register forces a would-be clear to caution (the listing verdict enum is unchanged).
  • Screening responses are no longer client-cacheable. They are served Cache-Control: private, no-store. Re-run a screen rather than replaying a stored response.
  • screening_id values changed at this epoch. The identifier now folds the coverage inputs that can flip a verdict, so ids minted before this release do not correspond to ids minted after. Do not treat a pre-release screening_id as stable across this boundary.
  • Watches are unchanged. Monitoring keeps office-based scoping and does not apply the protection-scope expansion, so a watch scoped to a country still watches that country’s office only (a DE watch does not surface EU trade marks). See Create Watch.

July 14, 2026

  • Compare (beta): POST /v1/compare, its TypeScript SDK resource, and its developer guide complete the public-facing Intelligence surface alongside Screening. Compare scores one candidate against up to 10 selected conflicts.