Skip to content

Webhook payload reference

Every field in an Embers webhook, from the envelope and version strings to the lead, engagement, contact, report, and test objects, and the key to join on.

Solo and above Updated 6 min read

Every Embers webhook is a JSON POST with the same envelope around an event-specific data object. This page lists every field, which ones to build on, and which ones are capped or conditional.

The envelope

FieldTypeWhat it is
idUUID stringThe event id. Equals the webhook-id header and stays the same on retries and replays
typestringOne of the event types below
api_versionstring2026-07-20. Covers transport: headers, signatures, delivery, and the ids you join on
schema_versionstring2026-09-10. Changes when a payload key is added or removed
created_atISO 8601When the event was created, not when this attempt was sent
accountobjectid (the workspace UUID) and name
dataobjectShaped by type

account lets an agency route events from several client workspaces through one receiver. The 2026-09-10 schema dropped account.type, so route on account.id. Ignore keys you do not recognise.

Event types

Typedata carries
lead.createdlead and engagement (recent form)
lead.engagement.addedlead and engagement (batched form)
lead.status_changedlead, engagement (recent form), previous_status, status, changed_at
report.generatedreport, reason, generated_at
webhook.testis_test, sample_event_type, and the sample shape of that event

Send lead events to your own endpoint covers when each one fires.

The lead object

data.lead is the same on every lead event.

FieldTypeNotes
idUUID stringThe Embers member id. See join on linkedin_urn
namestringFull name. There is no first or last name field
headlinestringThe LinkedIn headline
titlestringCurrent title, falling back to the current role, then the headline
companystringCurrent company, falling back to the current role
industry, locationstringAs stored on the profile
linkedin_urlstringProfile URL. Can change
linkedin_urnstringLinkedIn’s immutable member id. Can be blank on older records
scoreintegerLead score, 0 to 100, as shown in the app. See how lead scoring works
icp_matchboolean or nullnull means not yet classified
icp_confidenceinteger0 to 100
icp_reasonstringOne sentence on why the lead matched or did not
trendstringrising, stable, or cooling
top_signalsarray of stringsThe signals behind the score
sourcesarray of stringsAgents that found them: post_engagement, comment_engagement, competitor_engagement, keyword_tracking, qualify_post
statusstringPipeline status after the event
follower_countinteger or nullDivisor for the engagement rate
first_seen_atISO 8601 or nullWhen Embers first saw this person
work_historyarrayUp to 10 roles: company, title, start_date, end_date, location, industry. No job descriptions
certificationsarrayUp to 10: name, authority, date
contactobjectPaid plans only. See contact fields

Status values are active (shown as Pending in the app), contacted, replied, call_booked, not_interested, and dismissed. The leads list describes each one.

Two numbers the app shows are derived rather than sent. Engagement rate is engagement_count divided by follower_count. Grade comes from score: A at 80 or more, B at 60, C at 40, D at 20, F below that.

Join on linkedin_urn

Join people on lead.linkedin_urn. Do not key on linkedin_url: people change their vanity slug, and some are only ever seen in URN form, so one person can appear under two URLs. lead.id is stable per workspace and person, but when two member records are merged the losing id stops appearing. When linkedin_urn is blank on an older record, fall back to lead.id.

Contact fields

lead.contact appears only when the workspace is on a paid Solo plan or above. On Free, and during the free trial, the key is omitted entirely.

FieldNotes
email, phoneStored values only, otherwise null
includedtrue only when a stored email or phone exists
enriched_at, last_verified_atWhen the contact was enriched, or null
source, confidenceWhere it came from (harvest or apify) and how sure (safe, verified, or risky), or null
statusAlways ready

A webhook never triggers a fresh lookup and never invents an address. Reveal a lead’s email and phone explains how contacts get stored. Comment text can still contain details a person published, but that is public post content, not the contact object.

The engagement object

On lead.created, lead.status_changed, and test samples of them, data.engagement is the recent form:

  • recent: the lead’s 10 most recent engagements, newest first.
  • by_type: counts by engagement_type across those 10.
  • first_engaged_at, last_engaged_at: the range they cover.

On lead.engagement.added it is the batched form, one event per lead per scan:

  • engagement_count: how many engagements Embers first saw between window_start and window_end.
  • engagements: the lead’s most recent engagements, newest first, up to 50. It can include some that an earlier event already carried.
  • truncated: true when engagement_count is larger than the array.

Embers sends at most 500 lead.engagement.added events per workspace per scoring pass.

Fields on each engagement item
FieldNotes
engagement_typeLinkedIn’s own value, such as comment, comment_reply, repost, praise, or keyword_authored
engagement_categoryBranch on this: comment, reply, reaction, repost, or authored_post
engaged_at, engaged_at_precisionSee below
sourcepost (your posts), comment (your comments elsewhere), competitor, or keyword
comment_textThe comment or reply, up to 500 characters, ending in ... when cut
post_url, post_snippetThe post, with up to 280 characters of its text
post_author_name, post_author_typepost_author_type is you, competitor, third_party, or lead
competitor_nameSet on competitor engagement, otherwise empty
intent_categorypurchase_intent, pain_alignment, advocacy, question, casual, or unknown
matched_keywordsKeyword items only: the tracked phrases the post matched

engaged_at_precision is exact for comments and replies, which carry a LinkedIn timestamp. Everything else, including reactions, reposts, and keyword posts, is approximate: Embers substitutes the time it first saw the engagement or the post’s own date. Order a follow-up sequence on exact rows only.

Status, report, and test fields

lead.status_changed adds previous_status, status, and changed_at beside lead. Blocking a company sends one with status set to dismissed.

report.generated carries data.report with id, title, status, date_range, date_start, date_end, share_url (the public link), and view_count, plus reason (created or regenerated) and generated_at. It leaves out the report snapshot. See client reports.

webhook.test carries is_test: true, sample_event_type, and a sample of that event with placeholder data. A sample includes contact when your plan would.

Example lead.status_changed payload
{
  "id": "e1b4f6e8-4c4a-4f50-b3c7-2ef2f97d5012",
  "type": "lead.status_changed",
  "api_version": "2026-07-20",
  "schema_version": "2026-09-10",
  "created_at": "2026-07-20T10:00:00+00:00",
  "account": {
    "id": "4d2f0eb9-81e5-4f20-8a60-25cbb9fe9ea5",
    "name": "Acme LinkedIn"
  },
  "data": {
    "lead": {
      "id": "967caf1c-c0a6-4b98-9f3b-1e0811fb53b4",
      "name": "Alex Smith",
      "headline": "VP Sales at Acme",
      "title": "VP Sales",
      "company": "Acme",
      "industry": "Insurance",
      "location": "Chicago",
      "linkedin_url": "https://www.linkedin.com/in/alex-smith/",
      "linkedin_urn": "ACoAAABBBCCCDDDEEEFFFGGG",
      "score": 82,
      "icp_match": true,
      "icp_confidence": 90,
      "icp_reason": "Insurance principal with clear sales authority.",
      "trend": "rising",
      "top_signals": ["Commented on multiple posts"],
      "sources": ["post_engagement"],
      "status": "contacted",
      "follower_count": 4200,
      "first_seen_at": "2026-06-02T09:15:00+00:00",
      "work_history": [
        {
          "company": "Acme",
          "title": "VP Sales",
          "start_date": "2021-04",
          "end_date": "",
          "location": "Chicago",
          "industry": "Insurance"
        }
      ],
      "certifications": [],
      "contact": {
        "email": "a***@acme.example",
        "phone": null,
        "enriched_at": "2026-07-01T00:00:00+00:00",
        "last_verified_at": "2026-07-01T00:00:00+00:00",
        "included": true,
        "source": "harvest",
        "confidence": "safe",
        "status": "ready"
      }
    },
    "engagement": {
      "recent": [
        {
          "engagement_type": "comment",
          "engagement_category": "comment",
          "engaged_at": "2026-07-19T14:02:00+00:00",
          "engaged_at_precision": "exact",
          "source": "post",
          "comment_text": "This matches what we see at renewal.",
          "post_url": "https://www.linkedin.com/feed/update/7481311828074078208/",
          "post_author_name": "Your Name",
          "post_author_type": "you",
          "post_snippet": "A post about renewal cycles in commercial insurance.",
          "competitor_name": "",
          "intent_category": "pain_alignment"
        }
      ],
      "by_type": { "comment": 1 },
      "first_engaged_at": "2026-07-19T14:02:00+00:00",
      "last_engaged_at": "2026-07-19T14:02:00+00:00"
    },
    "previous_status": "active",
    "status": "contacted",
    "changed_at": "2026-07-20T10:00:00+00:00"
  }
}

Frequently asked questions

Why is there no first name or last name in the payload?
The payload carries one name field. HubSpot contacts and a CSV export with split names give you first and last names; the webhook does not.
Will a new field break my receiver?
Not if you ignore keys you do not recognise. Almost every change is additive. The one removal so far, account.type on 2026-09-10, bumped schema_version.
Why is lead.contact missing from my payloads?
The workspace is on Free or still in its free trial. Contact details reach the webhook on a paid Solo plan or above.

Was this article helpful?

Your first 2,000 engagers free

Every day Embers reads the public activity around your market, ranks the people who fit, and hands you a short list with the reason each one surfaced. You decide who to contact.

Start free trial
  • No card to start
  • No LinkedIn login
  • Cancel anytime

↑↓ to move ↵ to open esc to close