TL;DR: Send intent events from your stack into Unstuck. The API normalizes them into the same signal model as the built-in sources, runs qualification, and lands records in Leads.
When to use it
Three patterns:
- Custom intent capture. Your product has a high-intent moment (e.g. "user invited a teammate", "user enabled SSO") that Unstuck's built-in signal types don't cover. Send it as a custom signal.
- Legacy systems. Your existing intent-data vendor doesn't have a direct Unstuck connector. Pipe their output through the Signals API.
- AI agents. Your LLM agent discovered a buyer signal somewhere. POST it as a signal so it flows through the same qualification engine as everything else.
Endpoint
POST /signals
Headers:
Authorization: Bearer <UNSTUCK_API_KEY>
Content-Type: application/json
Body:
{
"signal_type": "custom_event",
"source": "your-system-name",
"event_name": "user_invited_teammate",
"occurred_at": "2026-05-26T14:30:00Z",
"identity": {
"email": "person@company.com",
"linkedin_url": "https://...",
"company_domain": "company.com",
"first_name": "...",
"last_name": "...",
"title": "..."
},
"context": {
"team_size": 12,
"plan_tier": "free"
}
}
Required fields:
signal_type— must be a Signal type that's enabled in your workspace (custom or built-in)source— the system that originated the event (free string; appears in attribution)occurred_at— ISO 8601 timestampidentity— at least one of email / linkedin_url / company_domain
Optional:
event_name— sub-classifier withinsignal_typecontext— arbitrary JSON. Stored alongside the signal capture; usable in audience conditions viasignals.context.team_size > 10
Response
{
"signal_capture_id": "sig_capture_abc123",
"matched_record_id": "lead_xyz789",
"qualification": {
"icp_code": "Mid-market SaaS",
"icp_score": 73,
"persona_code": "VP Engineering",
"persona_score": 81
}
}
If qualification ran (autoqualify is on for the signal_type), the response includes the qualification result. If autoqualify is off, qualification fields are null and you'd query them separately later.
Defining a custom signal type
Before sending custom-type events, declare the signal in the workspace:
Signals → + Add → Custom signal →
- Name — what shows up in the Signals table
- Source description — for documentation
- Default sub-rules (optional) — for filtering custom events into named buckets
- Autoqualify — on / off
Once declared, your signal_type in the API body matches the declared name (lowercased, underscored).
Idempotency
The Signals API is idempotent on (signal_type, source, identity, occurred_at). Sending the same event twice doesn't double-capture. Useful when your delivery is at-least-once.
To force a re-process (rare — usually for testing), include idempotency_key as a unique string in the body.
Rate limits
- 500 events per minute per workspace
- 50,000 events per day per workspace
- Higher limits available — contact us
Sending signals in without the API
If all you need is to get events into Unstuck Engine, the Webhook signal is usually less work than the API. It mints a URL per endpoint on the signal's own detail page, accepts any JSON shape, and needs no key management. See Replies and Conversions for how those inbound endpoints work.