Most of what you want to [segment](/audience/segments) or [trigger a workflow](/workflows/triggers) on doesn't originate inside SendOps. A contact's **plan** lives in your billing system; whether they've **finished onboarding** lives in your product database; a downstream account's **status** lives in that account. SendOps only sees the mail it sends and the [activities](/audience/activities) you push to it — so anything that happens elsewhere has to be **carried in**.

The way to carry it in is a **scheduled reconciliation sweep**: on a timer (or off a change-data-capture stream or webhook), read your source of truth and push the current picture into SendOps. There are two things to push, and the distinction matters.

## Attributes for state, activities for milestones

- **Current state → [attributes](/audience/attributes).** A value that has a *current answer* — plan, lifecycle stage, health score — is an attribute. Your sweep upserts it to match your source of truth; the newest write wins, and Segments read the latest.
- **Milestones → [activities](/audience/activities).** Something that *happened at a point in time* — they upgraded, they connected an account, they went live — is an activity. Activities are append-only and keep their history, so a Drip Workflow can enroll the moment one is recorded, and Segments can count them.

Most sweeps write both for the same change: the attribute so rules see the standing fact, and a milestone activity so a workflow can fire on the edge.


  A nightly job reads your billing system. For a customer who just upgraded it upserts `attr.plan = "pro"` (state) **and** records an `upgraded` activity (milestone). A "welcome to Pro" workflow triggers `enter on activity.upgraded`; a "Pro customers" Segment selects `attr.plan = "pro"`. The attribute keeps the Segment correct for as long as they stay on Pro; the activity is the one-time moment the workflow reacts to.


## Why you can't just observe it

Two things you might reach for instead **stop at the org boundary** — which is the whole reason the sweep exists:

- **Derived attributes are intra-org.** A [derived attribute](/audience/attributes#derived-attributes) such as `exists(send)` or `count(activity.order)` aggregates over *this contact's own stream, in this org*. It answers "has this person ever been sent mail **by us**" — never "has this person ever sent mail from **their own** account." If the behaviour happened in another system or another org, there's no stream here to aggregate; you have to write the fact in yourself.
- **Account state is caller-scoped.** The API's account snapshot describes *your* org's onboarding and AWS state — there's no way to read another org's. If each of your signups is their own SendOps org, you observe each one with *its own* key and reconcile the result onto a contact in your marketing org.


  Pushing an activity for someone SendOps has never seen creates a **stub contact** — it counts in Segment rules but isn't mailable until a contact write gives it an email and consent. If your milestone is meant to *trigger a send*, make sure the reconciliation upsert (which carries email and consent) runs too. See [Consent & lifecycle mail → activity ingest creates non-mailable stubs](/sending-email/consent-and-lifecycle#activity-ingest-creates-non-mailable-stub-contacts).


## Doing it over the API

The two primitives are both idempotent and safe to re-run on every sweep:

- **`PUT /v1/contacts/by-external-id/{external_id}`** upserts state keyed by *your* stable id — it converges on the same contact forever, so a nightly re-run is harmless.
- **`POST /v1/activities`** records milestones; give each logical milestone a stable `idempotency_key` so a re-scan doesn't double-record it.

The [developer guide — Syncing externally-observed state](https://developers.sendops.dev/api-reference/syncing-external-state) has the full request shapes, a runnable reconciliation loop, and the cross-org example.

## What's next?

- [Attributes](/audience/attributes) — the registry, per-contact values, and derived attributes.
- [Activities](/audience/activities) — recording behavioral signals and triggering workflows on them.
- [Triggers & enrollment](/workflows/triggers) — enrolling a workflow on a milestone activity.