The Signals REST API lets you send user intent signals directly via HTTP. This is useful when you already have structured signal data (e.g., IAB categories, page context, or parsed user intent) and want to send it without setting up an MCP connection.
The MCP Signal Server is the preferred method for signal collection. It allows the LLM to automatically extract signals from conversations. Use the REST API when you have pre-structured signal data or need to send signals from non-MCP environments.
Endpoint
POST https://zeroclick.dev/api/v2/signals
Authentication
Requires an API key via the x-zc-api-key header:
x-zc-api-key: your-api-key
Request Body
| Field | Type | Required | Description |
|---|
signals | array | Yes | Array of 1-10 signal objects (see Signal Fields) |
userId | string | No | Stable user identifier for analytics and personalization. Does not need to be your internal ID — can be a hash, as long as it is deterministically assigned to a user |
userSessionId | string | No | Stable session identifier. Does not need to be your internal session ID — can be a hash, as long as it is deterministically assigned to a session |
userLocale | string | No | User locale (e.g., en-US) |
userEmailSha256 | string | No | SHA-256 hash of user email for identity matching |
userPhoneNumberSha256 | string | No | SHA-256 hash of user phone for identity matching |
groupingId | string | No | Grouping ID for analytics segmentation |
ipAddress | string | No | Client IP address |
userAgent | string | No | Client User-Agent string |
Signal Fields
Each signal object in the signals array accepts the same fields as the MCP broadcast_signal tool. See the Tool Reference for the complete field reference.
Required: category, confidence, subject
Optional: relatedSubjects, sentiment, attributes, iab, extractionReason, sourceContext, eventTimestamp
Response
Returns 204 No Content on success.
Examples
Basic Signal
await fetch("https://zeroclick.dev/api/v2/signals", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-zc-api-key": "your-api-key"
},
body: JSON.stringify({
userId: "user-12345",
ipAddress: "your-user-ip-address",
signals: [
{
category: "purchase_intent",
confidence: 0.9,
subject: "Nike running shoes",
sentiment: "positive"
}
]
})
});
IAB Content Categories
You can send IAB Content Taxonomy signals to describe what the user is currently engaging with. Use the iab field with type: "content" and provide the IAB category IDs.
For example, if a user is reading a news article about marathon training:
await fetch("https://zeroclick.dev/api/v2/signals", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-zc-api-key": "your-api-key"
},
body: JSON.stringify({
userId: "user-12345",
ipAddress: "your-user-ip-address",
signals: [
{
category: "interest",
confidence: 0.85,
subject: "Running & Jogging",
relatedSubjects: [
"Athletic Shoes",
"Fitness Equipment",
"Sportswear"
],
sentiment: "positive",
iab: {
type: "content",
version: "2.2",
ids: ["607", "606", "604", "123"]
}
}
]
})
});
IAB Audience Segments
You can send IAB Audience Taxonomy segments using the iab field with type: "audience". Use user_context as the signal category to indicate these describe the user rather than the content they’re viewing.
For example, if you know from your user data that a user is a fitness enthusiast and outdoor adventurer:
await fetch("https://zeroclick.dev/api/v2/signals", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-zc-api-key": "your-api-key"
},
body: JSON.stringify({
userId: "user-12345",
ipAddress: "your-user-ip-address",
signals: [
{
category: "user_context",
confidence: 0.9,
subject: "Fitness Enthusiasts",
relatedSubjects: [
"Outdoor Adventurers",
"Marathon Runners"
],
iab: {
type: "audience",
version: "1.1",
ids: ["1234", "1235", "1236"]
}
}
]
})
});
Multiple Signals with Identity
await fetch("https://zeroclick.dev/api/v2/signals", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-zc-api-key": "your-api-key"
},
body: JSON.stringify({
userId: "user-12345",
ipAddress: "your-user-ip-address",
userSessionId: "session-abc",
userLocale: "en-US",
signals: [
{
category: "evaluation",
confidence: 0.8,
subject: "cloud hosting solutions",
relatedSubjects: ["AWS", "Google Cloud", "Azure"],
sentiment: "neutral",
attributes: {
budget: "enterprise",
timeline: "Q2 2026"
}
},
{
category: "business_context",
confidence: 0.9,
subject: "enterprise SaaS company",
attributes: {
team_size: "50-100",
industry: "fintech"
}
}
]
})
});
Signals in Offer Requests
You can also pass signals directly in the offers endpoint request body using the signals parameter. This is convenient when you want to send contextual signals at the same time as fetching offers:
const response = await fetch("https://zeroclick.dev/api/v2/offers", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-zc-api-key": "your-api-key"
},
body: JSON.stringify({
method: "server",
ipAddress: clientIpAddress,
query: "best running shoes",
limit: 3,
signals: [
{
category: "purchase_intent",
confidence: 0.9,
subject: "running shoes",
sentiment: "positive"
}
]
})
});
Signals passed in offer requests are stored in the same way as signals sent to /api/v2/signals. They contribute to the user’s preference profile for future offer matching.
When to Use Each Method
| Method | Best For |
|---|
| MCP Signal Server | AI agents that converse with users - the LLM automatically extracts signals |
REST API (/api/v2/signals) | Pre-structured data like IAB categories, page context, or parsed analytics |
Offers API (signals param) | Sending contextual signals alongside an offer request in a single call |