Core concepts
Targets and keywords are different things
A target is an account you watch; you get everything it does, or only the event types you choose. A keyword is a query you watch across all of X; you get posts from anyone that match it, as search.match events. Targets are identified by handle, keywords by the query text, and a key holds any number of each up to its plan's caps.
An account is its id, not its handle
You monitor an account, identified by its numeric X id (id on a Target). An account can change its handle (screen_name) or display name at any time: you keep receiving its events, later events carry the new handle in target.screen_name, and a profile.screen_name or profile.name event tells you what changed. Key your records on id. Wherever the API takes an account you can name it by its user_id, its current handle or a handle it had before.
Two-phase delivery: create, then update
Some post events are delivered in two frames. The first, op: "create", carries the essentials — the post id, the author and the text — so you can act on it immediately. A moment later the same event id arrives again with op: "update", now carrying media, the quoted or replied-to original, counts and the rest. Events that are complete when first seen have no second frame; GET /v1/meta/event-types says which types can have one.
create. If you need the whole post, wait for update on the same id. Either way, key your storage on id and let a later update overwrite what you kept. The type changes between the two frames in one way only: a first tweet.create with kind_final: false can become tweet.quote. If you treat original posts and quotes differently, sort such a frame once its update arrives.At-least-once, never exactly-once
Every monitored account is watched by several independent paths at once, so that one failing path costs you nothing. The first to report a given change wins and becomes the event; the others are recorded as corroboration rather than delivered again. Across a reconnect, however, you may see an event you already have. Deduplicate on id.
Position and replay
Each event carries a sid — its position in our log. Persist the last one you processed; on reconnect, pass it as ?last_id= and we send everything after it before resuming live. The log holds 24 hours, and a single reconnect replays at most 5,000 events. Targets or keywords you add while a socket is open start flowing on it within 30 seconds; you do not need to reconnect.