Skip to main content
Signals are detected events that indicate buying intent or a relevant business change at a target company. Puffle monitors data sources continuously and surfaces signals that match your configured signal types. Examples:
  • A company in your ICP posted a VP of Engineering role on LinkedIn (Hiring signal)
  • A lead’s company announced a Series B funding round (Funding signal)
  • A founder published a Reddit post complaining about an alternative tool (Pain Point signal)
Each signal carries a sellability score of 1, 2, or 3: 1 is irrelevant and filtered out before reaching the feed, 2 is worth knowing, and 3 is easy-sell-now. Items below 2 are dropped by the scorer and never reach your feed.

Signal types

Signal types define what Puffle monitors. There are two kinds:

Built-in types

Six pre-configured types are auto-seeded on first API call: Hiring, Funding, Leadership Change, Competitor Mentions (structured), plus Pain Point and Product Launch (keyword). They are always present on your account. You can tune their keywords, source selection, and enabled state, but not rename or delete them.

Custom types

Fully user-defined keyword types. You specify keywords, a free-form prompt describing what to detect, and which sources to monitor. Accounts can have up to 20 signal types total across built-in and custom types.
Structured built-in types use a form-driven structuredConfig JSON object that is compiled into keywords and prompts at scan time. Hiring, Funding, Leadership Change, and Competitor Mentions are structured types, so you edit their config instead of raw keywords. Keyword types, including Pain Point, Product Launch, and custom types, use explicit keywords[] plus a natural-language prompt.

Data sources

Puffle’s active signal source registry is defined in lib/signals/registry.ts:
SourceIdentifierDescription
LinkedIn Postslinkedin_postsPublic posts from company pages and individuals
LinkedIn Jobslinkedin_jobsJob postings on LinkedIn
NewsnewsNews articles from the news waterfall
Hiring.cafehiring_cafeHiring signal data
RedditredditPosts and comments matching keywords
Hacker Newshacker_newsHN posts
X / Twitterx_twitterPublic tweets
Each structured built-in is restricted to a subset of these sources, such as Hiring sourcing from linkedin_jobs, hiring_cafe, and linkedin_posts only. Custom keyword types may target any source.

Signal lifecycle

Data source crawled -> AI relevance filter -> entity extraction ->
hard filter (strict per-item gate) -> scorer (1-3 sellability) ->
Signal appears in your feed -> You vote, comment, draft outreach, or dismiss
Signals appear in your feed ordered by createdAt, newest first by default, with optional sortBy=score. Dismissal flows through PATCH /signals with status: "dismissed". Dismissed signals are removed from the active feed but remain accessible with GET /signals?includeDismissed=true.

API surface

All endpoints below accept Authorization: Bearer pk_live_* and return the structured { error: { code, message } } shape on failure. See the API overview for authentication, pagination, and rate-limit details.
EndpointDescription
GET /signalsRead your signal feed (cursor-paginated)
PATCH /signalsBatch vote, comment, attach DM or comment drafts, or set status including dismissal
GET /signals/leadsPeople and companies aggregated from your feed
PATCH /signals/leadsBatch update lead workflow status (new, contacted, or dismissed)
GET /signals/typesList signal type configurations and auto-seed built-ins
POST /signals/typesCreate a custom keyword type
PATCH /signals/typesBatch update existing types
DELETE /signals/typesBatch delete custom types; built-ins are protected
GET /signals/sourcesAdapter registry merged with your enable state
PATCH /signals/sourcesToggle or configure sources; cascades to type rows
GET /signals/settingsRead scan schedule and paused flag
PATCH /signals/settingsUpdate scan schedule and paused flag
GET /signals/searchList freeform signal searches
POST /signals/searchStart a freeform signal search
GET /signals/analyticsKeyword performance and run history
POST /signals/generateGenerate DM or comment drafts for a batch of signals
Mutations are batch-only: even a single update is wrapped in an items: [...] array, and the response carries a { updated|deleted: string[], errors?: [{ id, error }] } envelope so partial failures surface per item without rolling back the rest of the batch.

Leads

Signals can point to leads worth adding.

Campaigns

Campaigns turn signal-informed priorities into outreach.