Skip to main content
POST
/
api
/
v1
/
signals
/
types
Create a custom signal type
curl --request POST \
  --url https://app.puffle.ai/api/v1/signals/types \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "<string>",
  "keywords": [
    "<string>"
  ],
  "search_instructions": "<string>",
  "scoring_criteria": "<string>",
  "sources": [
    "news"
  ],
  "description": "<string>",
  "enabled": true
}
'
{
  "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "label": "<string>",
  "description": "<string>",
  "kind": "structured",
  "enabled": true,
  "keywords": [
    "<string>"
  ],
  "disqualifiers": [
    "<string>"
  ],
  "config": {},
  "config_schema": {},
  "built_in": true,
  "search_instructions": "<string>",
  "scoring_criteria": "<string>",
  "sources": [
    "news"
  ]
}

Overview

Creates a custom keyword-based signal type for the authenticated partner. The new type is immediately enabled and scans on the next scheduled run (unless enabled: false is passed). Required fields:
  • name — unique display name (1-100 chars, case-sensitive uniqueness per caller)
  • keywords — 1-50 non-empty search terms, applied across all enabled sources
  • search_instructions — prompt telling the scanner what content to look for
  • scoring_criteria — prompt telling the scorer how to rank matches
  • sources — at least one source from: news, reddit, hacker_news, x_twitter, linkedin_posts, linkedin_jobs, g2_capterra
Server-side, creation also seeds one signal_type_sources row per registered source, enabling only those listed in sources. You can tweak per-source behavior later via PATCH /api/v1/signals/types/{id}/sources/{sourceId}. Callers are capped at 20 total signal types. Attempting to create a 21st returns 400. Prompt reset. There’s also POST /api/v1/signals/types/{id}/reset — it restores search_instructions and scoring_criteria on BUILT-IN types to their system defaults. It does not apply to custom types (use PATCH to edit prompts directly).

AI agent notes

Lazy auto-configure. Creating a type requires supplying prompts upfront. If you’d rather have the system generate them from the caller’s company context, create a minimal type first (valid keywords + short placeholder prompts) and immediately call POST /api/v1/signals/types/{id}/generate — the background task fills in production-quality prompts.Source scope is later edited per-source. sources on create is a simple allowlist. Fine-grained control (per-source extra keywords, prompt overrides) is managed through the sources subresource.Uniqueness is per-caller. Two different partners can both have a layoffs type; conflicts are 409 only when the same caller tries it twice.This is the public partner API — rate-limited at 100 req/min. Use this rather than the internal /api/signals/types endpoint.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json

Create a custom keyword signal type. Users are capped at 20 total types.

name
string
required

Display name. Must be unique across the caller's types.

Required string length: 1 - 100
keywords
string[]
required

Search terms used across all enabled sources. 1-50 non-empty strings.

Required array length: 1 - 50 elements
Minimum string length: 1
search_instructions
string
required

Prompt telling the scanner what kind of content to look for. Required.

Minimum string length: 1
scoring_criteria
string
required

Prompt telling the AI how to rank/score hits for relevance. Required.

Minimum string length: 1
sources
enum<string>[]
required

At least one source must be enabled.

Minimum array length: 1

External data source that feeds signals. A signal type can be scoped to any subset of sources; the scanner fans out across the enabled set and classifies each hit.

Available options:
news,
reddit,
hacker_news,
x_twitter,
linkedin_posts,
linkedin_jobs,
g2_capterra
description
string

Short description shown in the UI. Defaults to empty string.

Maximum string length: 500
enabled
boolean

Defaults to true — the new type scans on the next run.

Response

Signal type created. Returns the full type object.

Public signal type. Returned by every signal-type endpoint and referenced from each signal via its signal_type label.

id
string<uuid>
required
Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
label
string
required

Display name, shown in the UI and echoed as signal_type.

description
string
required
kind
enum<string>
required

structured — built-in type (hiring, funding, management_change, competitor_mentions) with a typed config payload. keyword — free-form user-defined type driven by keywords + search_instructions + scoring_criteria.

Available options:
structured,
keyword
enabled
boolean
required

If false, the scanner skips this type entirely.

keywords
string[]
required
disqualifiers
string[]
required

Exclusion phrases. An AI judge skips hits that match any disqualifier.

config
object
required

Structured-type payload. Keys depend on the underlying type (e.g. roles/seniority for hiring; stages/industries for funding). Null for keyword types.

config_schema
object
required

JSON Schema describing the shape of config. Null for keyword types — there's no structured config.

built_in
boolean
required

Built-in types cannot be renamed, deleted, or have their sources changed. Only their prompts, keywords, disqualifiers, and structured config are editable.

search_instructions
string | null
required
scoring_criteria
string | null
required
sources
enum<string>[] | null
required

Subset of sources enabled for this type. Null means no restriction was ever set; otherwise only listed sources feed this type.

External data source that feeds signals. A signal type can be scoped to any subset of sources; the scanner fans out across the enabled set and classifies each hit.

Available options:
news,
reddit,
hacker_news,
x_twitter,
linkedin_posts,
linkedin_jobs,
g2_capterra