Skip to main content
POST

Job Change Search

Cost: 10 credits per page. A page with no matches costs 0. Job changes are the highest-intent signal in B2B: a new VP of Engineering buys differently in week three than in month nine, and the person who just left your customer is the reason that account is about to churn. This endpoint returns those events as a feed you can poll. Each event says what happened (joined, left, title_change), when it happened, when we detected it, and who it happened to — with the person and the company already attached, so a single call gives you something you can act on without a second lookup.

Freshness, and why staleness is ordered rather than hidden

Results are sorted by freshness. The feed opens with same-day detections; events we detected long after the fact surface as you page deeper. Every real dated event is included — a stale one is ordered later, never dropped. Each event carries detection_lag_days, the number of days between the change happening and our detection of it. Lower is fresher.
Poll page 1 on a schedule and stop as soon as detection_lag_days exceeds what you have already processed. That gives you the new events without paging through history every run.

Request body

string
Restrict to one kind of event. Omit to receive all three.
string | string[]
Filter to specific companies, by the organization_id returned on every event. Exact match, and more precise than a name search.Accepts an array or a comma-separated string. Up to 50 companies per request, counted across this field and company_urls together.
string | string[]
Filter to specific companies by LinkedIn company URL, or by the slug at the end of one. Use this the first time you track a company, when you do not have its organization_id yet — the response gives you the id to use from then on.
A company we do not yet track returns 400. Resolving a URL is slower than passing an id, so prefer the id once you have it.
string
Word-match on the new job title. Minimum 3 characters.Example: "Engineering" matches VP of Engineering and Engineering Manager.
string
Partial match on the person’s current city. Minimum 3 characters.Example: "Berlin"
string
Two-letter country code for the person’s current location. Case-insensitive.Example: "DE"
The two geo filters narrow the search but are not echoed back on the events — they filter on a location the event record does not carry. If you need the person’s location, fetch their profile with person.linkedin_url.
integer
Recency window on the detection time, in days. Range 1365. Omit it to search all events.Example: 7 returns everything detected in the last week, whenever the change itself happened.
integer
default:1
Page number, 1-based. Maximum 10000; anything higher returns 400.
integer
default:25
Events per page. Range 150.
This endpoint also accepts GET with the same attributes as query parameters, e.g. GET /api/v1/job-changes/search?event_type=joined&days_ago=7&title=Engineering.In a query string, list fields are comma-separated: ?organization_ids=dm_org_abc,dm_org_def.

Company filter options

Two ways to name a company — use whichever you have: Both can be combined in the same request. A company named by both counts once.

Working with ids

Every event carries two Datamagnet ids:
  • person.profile_iddm_prsn_…
  • organization.organization_iddm_org_…
They are stable: the same person and the same company are the same id in every response, for ever, so they work as keys in your own database. organization_id is Datamagnet’s own identifier for that company — the same one our company records are keyed by — so an id you store today keeps working as we add more about that company. To pull the full record behind an event, use the LinkedIn URL that comes with it:
  • person.linkedin_urlPerson
  • organization.linkedin_urlCompany

Response

Every event returns the same set of keys. A field an event does not have comes back as null rather than being omitted, so your parsing code never has to branch.

Dates, and the two of them

changed_at is when the change took effect. detected_at is when we saw it. detection_lag_days is the gap, in days. title.previous is only meaningful on title_change and left; a joined event has no title to have replaced, so it comes back null.

Pagination

pagination.has_more tells you whether another page exists. Keep incrementing page while it is true, up to the 10000 page cap. An empty data array with has_more: false means you have reached the end of the feed for those filters — and costs 0 credits.

Errors

Nothing is charged on any error.