How the feed works
- Each item is a
changewithtype: "trademark.changed"and the record as it is when you read the page. If a record changed twice since your last poll, you get it once, in its latest state. created_atis when the change was published to the feed. Items are ordered by it, and several items can share one timestamp.trademarkis a summary. Addinclude=full(withlimitup to 25) to get full records, or fetch the ones you need with batch retrieve.next_cursoris never null. It is your position in the feed; store it after every page.has_more: falsemeans you have everything published beforecomplete_through. Poll again later with the same cursor.- Ignore item types you do not know.
trademark.removedis reserved for a later version.
Subscribe
Choose your scope: the registers you want, asjurisdiction (up to 20 codes), or no jurisdiction for every register. Then call the feed once without since or cursor. This subscribes from now: you get an empty page and a cursor.
jurisdiction on every later call. A cursor is bound to its scope; a different scope gets 400 cursor-mismatch. To change scope, start a new subscription (and load any new register as below).
Initial load
The feed only carries changes. To start a copy, combine it with search, in this order:- Take a feed cursor first, by subscribing as above, and store it.
- Copy the current state of your scope with a search (for example
jurisdiction=AD,AL), fetching full records in batches. - Follow the stored cursor. Changes made while step 2 ran are replayed; because you upsert by
id, replaying them is harmless.
Feed history starts at
feed_start, when the feed was launched, not at the beginning of each register. Whole-register exports are not part of v1; for very large registers, talk to us before copying them through the API.The polling loop
- Store the cursor after every page, after the page’s records are saved. If you can, store it in the same transaction as the records. A crash then replays at most one page.
- Upsert by
trademark.id. Never append: the same record arrives again whenever it changes, and replays are normal. - Poll at most every 15 minutes. Changes are published in batches after each register update, so polling more often rarely finds anything new. A poll that returns no changes is not billed, but it still counts toward your per-minute rate limit.
- Keep the scope fixed. Send the same
jurisdictionon every call, and never sendsincetogether withcursor.
Starting from a time
Instead of subscribing from now, you can start from a past time withsince, an RFC 3339 timestamp with Z or an offset:
since is inclusive, because several changes can share one timestamp. It cannot be earlier than feed_start; an earlier value gets 400. Use since on the first call only, then follow the cursor.
Recovering a lost cursor
If your stored cursor is lost, or rejected with 400invalid-cursor, restart with since set to the created_at of the last item you processed. Items with that exact timestamp are delivered again; your upserts absorb them.
Reloads, bursts and removals
- A register that is reloading is skipped and listed in
unavailable_jurisdictions; its changes follow when the reload ends. If every register in your scope is reloading, the call gets 503jurisdiction-unavailablewithRetry-Afterof at least 900 seconds. Your cursor stays valid. - Reloads and processing changes republish many records at once. Compare the fields you care about before you raise alerts. See How records change.
- Records removed by an office are not announced in v1. Re-check the records you depend on with batch retrieve from time to time and handle
not_found.