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
Webhook callbacks (reverse direction)
You can register a webhook on the Signals API: every time a captured signal qualifies, Unstuck Engine POSTs to your endpoint with the qualification result. Useful for routing-on-qualification flows in your own system.
Register the webhook in Settings → API & Webhooks → Signal qualification webhook.