Download OpenAPI specification:
kenbun API for event ingestion, scoring, segments, triggers, and organization unit (OU) workflows. Notes on scoping and security:
# HELP events_ingested_total Total number of events ingested (accepted). # TYPE events_ingested_total counter events_ingested_total 0 # HELP queue_depth Current depth of the async processing queue. # TYPE queue_depth gauge queue_depth 0 # HELP event_to_slack_latency_seconds Latency in seconds from event ingestion to Slack notification. # TYPE event_to_slack_latency_seconds histogram # HELP http_requests_total Total number of HTTP requests by status code and method. # TYPE http_requests_total counter
Returns the authenticated user's basic profile. Requires a valid JWT.
{- "org_member_id": "om_abc123",
- "first_name": "Jane",
- "last_name": "Doe",
- "email": "jane@example.com",
- "role": "admin",
- "verified": true
}Requires authentication and an active OU selected via POST /org-units/active. The server derives org_id and unit_id from the authenticated context; clients must not send unit_id.
Identify the target lead with EITHER:
lead_id, ORaliases array (preferred). Each entry supplies alias_kind and raw_value.Backward compatibility: top‑level alias_kind and alias are accepted on ingest but are deprecated and not returned by read endpoints.
| lead_id | string Existing lead identifier; optional when aliases are provided |
| alias_kind | string Enum: "email" "phone" "external_id" "cookie" "social" Deprecated. Use |
| alias | string Deprecated. Use |
Array of objects Preferred. One or more aliases to identify or create a lead. | |
| event_type required | string |
| timestamp | string <date-time> |
object Arbitrary JSON metadata. Max 100KB; larger payloads are rejected with 413. For DECAY events, the server sets metadata.channel to 'system'. |
{- "lead_id": "ld_123",
- "event_type": "Page View",
- "timestamp": "2025-08-15T12:00:00Z",
- "metadata": {
- "path": "/pricing",
- "utm_source": "newsletter"
}
}{- "message": "event ingested",
- "metadata": {
- "geo_country": "US",
- "geo_region": "California",
- "geo_city": "San Francisco",
- "user_agent": "Mozilla/5.0"
}
}Accepts a CSV upload. The server enqueues each row as an EngagementEvent under the authenticated org and active OU. Required columns: event_type. Optional: lead_id, timestamp (RFC3339), metadata (JSON), alias columns (external_id,email,phone,cookie,social).
| file | string <binary> CSV file with header row |
{- "message": "string"
}Returns events limited to the active Organization Unit (OU).
| page | integer >= 1 Default: 1 |
| limit | integer [ 1 .. 500 ] Default: 50 |
| metadata | Array of strings Repeatable metadata key/value filters (e.g., metadata=utm_campaign:fall2025) |
| logic | string Default: "and" Enum: "and" "or" Combine metadata filters with AND (default) or OR |
[- {
- "id": "ev_001",
- "org_id": "org_1",
- "unit_id": "unit_default",
- "lead_id": "ld_123",
- "event_type": "Page View",
- "timestamp": "2025-08-15T12:00:00Z",
- "metadata": {
- "path": "/pricing"
}
}
]| leadID required | string |
[- {
- "id": "ev_002",
- "org_id": "org_1",
- "unit_id": "unit_default",
- "lead_id": "ld_123",
- "event_type": "signup",
- "timestamp": "2025-08-15T12:05:00Z"
}
]Returns per-ruleset score deltas and before/after totals for a single event.
| eventID required | string |
{- "event_id": "string",
- "lead_id": "string",
- "event_type": "string",
- "occurred_at": "2019-08-24T14:15:22Z",
- "rulesets": [
- {
- "ruleset_id": "string",
- "ruleset_name": "string",
- "is_primary": true,
- "score_delta": 0,
- "score_before": 0,
- "score_after": 0,
- "rule_weight": 0
}
]
}Returns a composite view of lead activity: filtered engagement events, orders, and a unified timeline.
Unified Activity Stream (ADR-0010):
engagement_events tableorders table (represented as synthetic activity projections)OU Scoping: Only returns data for the caller's active Organizational Unit.
Synthetic Order Projections:
orders array and timeline with type: "order"engagement_events tableFiltering behavior:
range, start, end: Apply to both events and orderschannel, minScore, maxLatency, hasDelta: Apply to events only| leadID required | string Lead UUID |
| range | string Default: "last_7d" Enum: "all" "last_7d" "last_24h" "last_30d" "last_90d" "today" "yesterday" "custom" Time range filter (applies to both events and orders) |
| start | string <date-time> Start timestamp (RFC3339, UTC). Required when range=custom |
| end | string <date-time> End timestamp (RFC3339, UTC). Required when range=custom |
| channel | string Enum: "all" "web" "email" "slack" "webinar" "crm" "system" Channel filter (applies to events only) |
| minScore | integer >= 0 Minimum score filter (applies to events only) |
| maxLatency | integer >= 1 Maximum latency in ms (applies to events only) |
| hasDelta | string Enum: "1" "true" "0" "false" Show only events with score deltas (applies to events only) |
{- "events": [
- {
- "id": "evt-123",
- "event_type": "Page View",
- "timestamp": "2025-11-15T09:00:00Z",
- "metadata": {
- "url": "/products/widget"
}, - "source": "web"
}
], - "orders": [
- {
- "id": "order-456",
- "type": "order",
- "timestamp": "2025-11-15T09:10:00Z",
- "order_id": "456",
- "total_amount": 129.99,
- "status": "completed",
- "items_summary": "2 items"
}
], - "timeline": [
- {
- "id": "evt-123",
- "ts": "2025-11-15T09:00:00Z",
- "title": "Page View",
- "type": "event",
- "subtext": "/products/widget",
- "jumpTo": "evt-123",
- "dotColor": "brand",
- "channel": "web"
}, - {
- "id": "order-456",
- "ts": "2025-11-15T09:10:00Z",
- "title": "Order Placed",
- "type": "order",
- "subtext": "$129.99 • 2 items • completed",
- "jumpTo": "order-456",
- "dotColor": "green",
- "channel": "order"
}
]
}Returns aggregated engagement scoring patterns across all closed-won deals in the active OU. Includes average lead scores at MQL, SQL, Opportunity, and Close milestones, and a ranked list of the event types most associated with closed pipeline. Use this to calibrate scoring thresholds and validate rule weights against real conversion data.
{- "closed_won_deals": 42,
- "avg_score_at_mql": 28.5,
- "avg_score_at_sql": 51.2,
- "avg_score_at_opportunity": 68,
- "avg_score_at_close": 84.7,
- "top_event_types": [
- {
- "event_type": "demo_request",
- "deal_count": 38,
- "total_points": 4200
}, - {
- "event_type": "page_view",
- "deal_count": 42,
- "total_points": 3150
}, - {
- "event_type": "email_open",
- "deal_count": 31,
- "total_points": 1900
}
]
}Returns campaign performance aggregated from UTM parameters on engagement events in the
active Organizational Unit. Each row represents a unique value of utm_campaign,
utm_source, or utm_medium depending on group_by. Pipeline metrics are computed via
the lead → account → deal join and are multi-touch and unweighted; the same deal counts
in full toward every campaign that touched the account.
| group_by | string Default: "campaign" Enum: "campaign" "source" "medium" Which UTM key to aggregate on. Defaults to |
| start_date | string Lower bound for event |
| end_date | string Upper bound for event |
{- "group_by": "campaign",
- "campaigns": [
- {
- "name": "spring-2026-launch",
- "total_events": 1284,
- "unique_leads": 312,
- "mql_count": 47,
- "total_points": 6420,
- "deals_count": 12,
- "pipeline_value": 485000,
- "closed_won_value": 120000,
- "first_event_at": "2026-03-01T08:14:22Z",
- "last_event_at": "2026-03-31T19:42:01Z"
}
]
}Returns up to 500 leads attributed to a specific UTM value, ordered by earliest first touch (most recent first). Use this drilldown after listing campaigns from the aggregate endpoint to inspect contact-level detail, account linkage, and deal context.
| campaign_name required | string Exact UTM value to look up. URL-encode if it contains spaces or special characters. |
| group_by | string Default: "campaign" Enum: "campaign" "source" "medium" Which UTM key to match |
| start_date | string Lower bound for event |
| end_date | string Upper bound for event |
{- "campaign_name": "string",
- "leads": [
- {
- "lead_id": "9bddab70-98e6-43a9-8f32-c9788b9de0c0",
- "display_name": "string",
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "title": "string",
- "company": "string",
- "score": 0,
- "level": "string",
- "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
- "account_name": "string",
- "deal_stage": "string",
- "deal_amount": 0,
- "first_touch_at": "2019-08-24T14:15:22Z",
- "last_touch_at": "2019-08-24T14:15:22Z"
}
]
}Returns scores for the provided lead_ids under the active OU. If ruleset is omitted or set to primary,
the primary engagement ruleset is used. If no primary exists, all scores are returned as 0.
| lead_ids required | Array of strings [ 1 .. 500 ] items |
| ruleset | string primary (default) or a specific ruleset_id/name |
{- "lead_ids": [
- "string"
], - "ruleset": "string"
}[- {
- "lead_id": "ld_001",
- "ruleset_id": "rs_abc",
- "ruleset_name": "Primary Engagement",
- "score": 32
}, - {
- "lead_id": "ld_002",
- "ruleset_id": "rs_abc",
- "ruleset_name": "Primary Engagement",
- "score": 18
}
]Reads a lead's score within the active OU. If ruleset_id is omitted, returns the highest score across all active rulesets for the active OU.
| leadID required | string |
{- "lead_id": "ld_123",
- "score": 87
}Returns lead scores for the active Organizational Unit (OU).
When page or limit is provided, the response includes pagination metadata (total, page, limit).
Notes:
| page | integer >= 1 Default: 1 |
| limit | integer [ 1 .. 500 ] Default: 50 |
| range | string Enum: "all" "today" "yesterday" "last_24h" "last_7d" "last_30d" "last_90d" Filter leads by created_at using a named range (e.g., last_7d). Also used for session counts. |
| min_score | integer Minimum total score. |
| max_score | integer Maximum total score. |
| event_type | string Filter by last event type per lead. |
| last_active | string Enum: "any" "7d" "30d" Filter by last activity recency (e.g., 7d or 30d). |
| include_disqualified | boolean Default: false When true, include disqualified leads. Defaults to false (qualified-only). |
{- "leads": [
- {
- "lead_id": "ld_001",
- "score": 32
}, - {
- "lead_id": "ld_002",
- "score": 28
}
], - "total": 2,
- "page": 1,
- "limit": 25
}| id required | string |
object | |
| account_id | string or null |
{- "id": "string",
- "metadata": { },
- "account_id": "string"
}{- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "account_id": "string",
- "owner_id": "string",
- "owner_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "merged_into": "string",
- "metadata": { }
}Downloads all leads matching the provided filters as a CSV file. Respects the same filter parameters as GET /leads. The response is a CSV attachment with columns for lead ID, alias, engagement score, profile score, engagement level, profile level, account, owner, last activity date, and creation date.
| min_score | integer Minimum engagement score filter |
| max_score | integer Maximum engagement score filter |
| engagement_level | string Filter by engagement level name |
| profile_level | string Filter by profile level name |
| search | string Search by email, alias, or lead ID |
| last_active | string Filter by recency (e.g., 7d, 30d) |
| sort_by | string Field to sort by (e.g., score, created_at) |
| sort_order | string Enum: "asc" "desc" |
Returns up to 10 leads matching a search query. Matches by lead ID prefix or alias value (email, phone, etc.). Used for autocomplete in the UI.
| q required | string >= 2 characters Search query (minimum 2 characters) |
[- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "match_type": "id",
- "best_alias": "string",
- "engagement_level": "string",
- "profile_level": "string"
}
]| leadID required | string |
{- "lead": {
- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "account_id": "string",
- "owner_id": "string",
- "owner_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "merged_into": "string",
- "metadata": { }
}, - "account": { }
}| leadID required | string |
{- "lead_id": "string",
- "score": 0,
- "disqualified": true,
- "disqualified_by_rule_id": "string",
- "disqualified_at": "2019-08-24T14:15:22Z",
- "disqualified_reason": "string"
}Returns the ranked scoring factors (engagement, profile, account) for a single lead, along with a plain-language summary line suitable for display in the lead list.
When the lead is disqualified, the response short-circuits to the DQ phrase:
the factors array is empty and the disqualification block is populated.
This is the GDPR Art. 22 audit surface.
| leadID required | string |
{- "lead_id": "string",
- "summary": "string",
- "factors": [
- {
- "dimension": "engagement",
- "rule_name": "string",
- "contribution": 0,
- "matched_value": "string",
- "event_count": 0,
- "days_since_fresh": 0,
- "phrase": "string"
}
], - "disqualified": true,
- "disqualification": {
- "rule_name": "string",
- "reason": "string",
- "at": "2019-08-24T14:15:22Z"
}
}Returns a plain-language "Why" summary string for each requested lead in one round-trip. Designed for the lead-list page where 50-200 rows each need a summary without issuing per-row API calls.
The endpoint issues at most 8 database queries regardless of N (the number of lead_ids), satisfying the O(1) query-count constraint for lead-list scale.
Disqualified leads short-circuit to their disqualification phrase only. This is the GDPR Art. 22 audit surface: a disqualified lead's "why" must always be the disqualification reason, never a stale engagement summary.
OU scoping: lead IDs that do not belong to the active OU appear in
missing[] without revealing whether the lead exists in another OU.
| lead_ids required | string Example: lead_ids=uuid-1,uuid-2,uuid-3 Comma-separated list of lead UUIDs. Maximum 200. Duplicates are silently de-duplicated. An empty value returns 200 with empty maps. |
{- "summaries": {
- "uuid-1": "Strong fit: VP at SaaS. Hot intent: pricing page 3x this week. Demo request 2 days ago.",
- "uuid-2": "Disqualified: no email AND no phone (today)."
}, - "missing": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}| leadID required | string |
{- "lead": {
- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "account_id": "string",
- "owner_id": "string",
- "owner_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "merged_into": "string",
- "metadata": { }
}, - "account": { }
}| leadID required | string |
object | |
| account_id | string or null |
{- "metadata": { },
- "account_id": "string"
}| id required | string |
object | |
| account_id | string or null |
{- "id": "string",
- "metadata": { },
- "account_id": "string"
}{- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "account_id": "string",
- "owner_id": "string",
- "owner_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "merged_into": "string",
- "metadata": { }
}| leadID required | string |
| property name* additional property | any |
{- "industry": "SaaS",
- "plan": "Pro"
}{- "id": "ld_123",
- "org_id": "org_1",
- "unit_id": "unit_default",
- "metadata": {
- "industry": "SaaS",
- "plan": "Pro"
}
}Resolves a lead from an alias such as an email address and returns the lead ID along with current metadata. Used by the Chrome extension Lead Profile tab to display the identified lead's profile attributes. OU-scoped -- only leads in the active Organizational Unit are searched.
| kind | string Default: "email" Alias type to search by. Defaults to "email". |
| value required | string The alias value to look up (e.g., the lead's email address). |
{- "lead_id": "ld_abc123",
- "email": "alex@example.com",
- "metadata": {
- "first_name": "Alex",
- "company": "Acme Corp",
- "quote_step": "Step 1"
}
}Resolves a lead from an alias (e.g., email) and merges the provided attributes into the lead's metadata. This is a silent update -- no event is created in the activity timeline. Used by the Chrome extension to annotate lead profiles with contextual information. OU-scoped -- the lead must exist in the active Organizational Unit.
| alias_kind | string Default: "email" Alias type. Defaults to "email". |
| alias_value required | string The alias value to resolve the lead (e.g., email address). |
object Key-value pairs to merge into the lead's metadata. Keys must be 1-64 characters and contain only letters, digits, underscores, dashes, dots, or spaces. Required if account_id is not provided. | |
| account_id | string Account ID to associate with this lead. Required if attributes is not provided. |
{- "alias_kind": "email",
- "alias_value": "alex@example.com",
- "attributes": {
- "quote_step": "Step 1",
- "interest_level": "high"
}
}{- "lead_id": "ld_abc123",
- "updated": 2,
- "attributes": {
- "quote_step": "Step 1",
- "interest_level": "high"
}, - "account_linked": false
}Consolidate multiple source leads into a target lead within the active OU. Moves events and aliases, marks sources as merged, and recomputes the target's lead scores. Cross-OU merges are not allowed. Default truncation policy is 'none'.
| targetLeadId required | string |
| sourceLeadIds required | Array of strings |
object |
{- "targetLeadId": "string",
- "sourceLeadIds": [
- "string"
], - "truncate": {
- "strategy": "none",
- "windowMinutes": 1,
- "keepTypes": [
- "string"
]
}
}{- "target": {
- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "account_id": "string",
- "owner_id": "string",
- "owner_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "merged_into": "string",
- "metadata": { }
}, - "mergedSources": [
- "string"
], - "movedEvents": 0,
- "truncatedEvents": 0,
- "rescore": {
- "mode": "inline",
- "taskId": "string"
}
}Returns top drivers, a rule weights snapshot, and surge boost contributions for the specified lead. OU scoped; time window defaults to last 24 hours.
| leadID required | string |
| hours | integer >= 1 Default: 24 |
{- "top_drivers": [
- {
- "rule_id": "string",
- "event_type": "string",
- "count": 0,
- "weight": 0,
- "total": 0,
- "filter_label": "string",
- "half_life_days": 0,
- "most_recent_at": "2019-08-24T14:15:22Z"
}
], - "snapshot": [
- {
- "event_type": "string",
- "weight": 0
}
], - "surge_boost": [
- {
- "base_event_type": "string",
- "total": 0,
- "events": 0,
- "avg_multiplier": 0
}
], - "surge_total": 0,
- "surge_event_count": 0,
- "decay_applied": 0,
- "inorganic_count": 0,
- "range_hours": 0,
- "score_reset_at": "2019-08-24T14:15:22Z",
- "reset_excluded_count": 0
}Zeros all engagement scores for the specified lead. Events and score history are preserved, but pre-reset event contributions are removed so backfills do not undo the reset. A score_reset event is logged in the timeline.
| leadID required | string |
{- "status": "ok",
- "lead_id": "string",
- "previous_scores": {
- "property1": 0,
- "property2": 0
}
}Assign a team member as the owner of a lead, or unassign the current owner by sending null values. The owner appears in lead list views and can be used for filtering and routing.
| leadID required | string <uuid> Lead identifier |
| owner_id | string or null User ID of the new owner. Send null to unassign. |
| owner_name | string or null Display name of the new owner |
{- "owner_id": "string",
- "owner_name": "string"
}{- "status": "ok",
- "message": "owner assigned"
}Assign an owner to multiple leads at once. Maximum 500 leads per request. Useful for routing batches of leads to a sales rep or reassigning leads in bulk.
| lead_ids required | Array of strings <= 500 items List of lead IDs to assign (max 500) |
| owner_id | string or null User ID of the owner. Send null to unassign. |
| owner_name | string or null Display name of the owner |
{- "lead_ids": [
- "string"
], - "owner_id": "string",
- "owner_name": "string"
}{- "status": "ok",
- "affected": 0
}| id required | string |
[- {
- "rule_id": "string",
- "ruleset_id": "string",
- "org_id": "string",
- "unit_id": "string",
- "event_type": "string",
- "weight": 0,
- "half_life_days": 1,
- "icon": "string",
- "active": true,
- "start_at": "2019-08-24T14:15:22Z",
- "end_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}
]Atomically sets the priority order of all rules in a ruleset. The order of rule_ids in the request body becomes the new priority order (first element = highest priority). Returns 204 on success.
| id required | string Ruleset identifier |
| rule_ids required | Array of strings Rule IDs in the desired priority order (highest priority first) |
{- "rule_ids": [
- "rule-789",
- "rule-123",
- "rule-456"
]
}| rule_id | string |
| ruleset_id | string |
| org_id | string |
| unit_id | string |
| event_type | string |
| weight | integer |
| half_life_days | integer or null [ 1 .. 730 ] Score half-life in days. When set, an event scored N days ago contributes weight × 0.5^(N/half_life_days). Range [1, 730]. Omit or send null to disable decay for this rule. |
| icon | string |
| active | boolean |
| start_at | string <date-time> |
| end_at | string <date-time> |
| created_at | string <date-time> |
| updated_at | string <date-time> |
| created_by | string |
| updated_by | string |
{- "event_type": "Email Open",
- "weight": 5,
- "active": true
}{- "rule_id": "rl_2",
- "ruleset_id": "rs_default",
- "event_type": "Email Open",
- "weight": 5,
- "active": true
}| id required | string |
| rule_id | string |
| ruleset_id | string |
| org_id | string |
| unit_id | string |
| event_type | string |
| weight | integer |
| half_life_days | integer or null [ 1 .. 730 ] Score half-life in days. When set, an event scored N days ago contributes weight × 0.5^(N/half_life_days). Range [1, 730]. Omit or send null to disable decay for this rule. |
| icon | string |
| active | boolean |
| start_at | string <date-time> |
| end_at | string <date-time> |
| created_at | string <date-time> |
| updated_at | string <date-time> |
| created_by | string |
| updated_by | string |
{- "rule_id": "string",
- "ruleset_id": "string",
- "org_id": "string",
- "unit_id": "string",
- "event_type": "string",
- "weight": 0,
- "half_life_days": 1,
- "icon": "string",
- "active": true,
- "start_at": "2019-08-24T14:15:22Z",
- "end_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}Evaluates a scoring rule configuration against a specific lead without modifying production scores. Returns whether the rule would match and how many points it would award.
| lead_id required | string The lead to test the rule against |
required | object The rule configuration to evaluate |
{- "lead_id": "string",
- "rule": {
- "event_type": "string",
- "weight": 0,
- "attribute_filters": [
- {
- "field": "string",
- "operator": "equals",
- "value": "string"
}
]
}
}{- "matches": true,
- "reason": "string",
- "current_score": 0,
- "projected_score": 0,
- "matching_events": 0
}Immediately rescores all leads in the active OU against the specified ruleset. Works for any scoring dimension (engagement, profile, account, deal).
| dimension required | string Enum: "engagement" "profile" "account" "deal" The scoring dimension |
| id required | string The ruleset identifier |
Returns all surge triggers for the active organizational unit.
[- {
- "trigger_id": "string",
- "event_type": "string",
- "window_seconds": 1,
- "window_unit": "seconds",
- "threshold_count": 1,
- "notification_channel_id": "443c093d-58e9-4719-a2d4-12f031de4a66",
- "webhook_url": "string",
- "warnings": [
- "string"
], - "emails": [
- "user@example.com"
], - "active": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]Creates a new surge trigger for the active organizational unit.
| event_type | string Optional; leave empty to monitor all event types |
| window_seconds required | integer >= 1 |
| window_unit | string Default: "seconds" Enum: "seconds" "minutes" "hours" "days" |
| threshold_count required | integer >= 1 |
| active | boolean Default: true Whether the trigger is active. Defaults to true. Pass false to save a draft without a dispatch destination. |
| notification_channel_id | string or null <uuid> ID of a saved Notification Channel (scoped to the active OU). Must be a valid UUID that belongs to the active organizational unit. Preferred destination — supersedes webhook_url. |
| webhook_url | string or null Deprecated Deprecated. Legacy webhook destination. Use notification_channel_id instead. When set, the response includes a deprecation warning in the warnings field. |
| webhook_auth_header | string Optional authorization header for webhook requests |
| emails | Array of strings <email> [ items <email > ] |
| slack_target_kind | string Enum: "channel" "user" Slack destination type |
| slack_target_id | string Slack channel or user ID |
| teams_webhook_url | string Microsoft Teams incoming webhook URL |
{- "event_type": "string",
- "window_seconds": 1,
- "window_unit": "seconds",
- "threshold_count": 1,
- "active": true,
- "notification_channel_id": "443c093d-58e9-4719-a2d4-12f031de4a66",
- "webhook_url": "string",
- "webhook_auth_header": "string",
- "emails": [
- "user@example.com"
], - "slack_target_kind": "channel",
- "slack_target_id": "string",
- "teams_webhook_url": "string"
}{- "trigger_id": "string",
- "event_type": "string",
- "window_seconds": 1,
- "window_unit": "seconds",
- "threshold_count": 1,
- "notification_channel_id": "443c093d-58e9-4719-a2d4-12f031de4a66",
- "webhook_url": "string",
- "warnings": [
- "string"
], - "emails": [
- "user@example.com"
], - "active": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Updates an existing surge trigger by ID.
| id required | string |
| event_type | string Optional; leave empty to monitor all event types |
| window_seconds required | integer >= 1 |
| window_unit | string Default: "seconds" Enum: "seconds" "minutes" "hours" "days" |
| threshold_count required | integer >= 1 |
| active | boolean Default: true Whether the trigger is active. Defaults to true. Pass false to save a draft without a dispatch destination. |
| notification_channel_id | string or null <uuid> ID of a saved Notification Channel (scoped to the active OU). Must be a valid UUID that belongs to the active organizational unit. Preferred destination — supersedes webhook_url. |
| webhook_url | string or null Deprecated Deprecated. Legacy webhook destination. Use notification_channel_id instead. When set, the response includes a deprecation warning in the warnings field. |
| webhook_auth_header | string Optional authorization header for webhook requests |
| emails | Array of strings <email> [ items <email > ] |
| slack_target_kind | string Enum: "channel" "user" Slack destination type |
| slack_target_id | string Slack channel or user ID |
| teams_webhook_url | string Microsoft Teams incoming webhook URL |
{- "event_type": "string",
- "window_seconds": 1,
- "window_unit": "seconds",
- "threshold_count": 1,
- "active": true,
- "notification_channel_id": "443c093d-58e9-4719-a2d4-12f031de4a66",
- "webhook_url": "string",
- "webhook_auth_header": "string",
- "emails": [
- "user@example.com"
], - "slack_target_kind": "channel",
- "slack_target_id": "string",
- "teams_webhook_url": "string"
}Backtests a surge trigger against the last N days (up to 90) of event history for the active organizational unit. Returns the number of times the trigger would have fired and a sample list of matching lead IDs.
No notifications are sent and the trigger state is not modified.
| id required | string Surge trigger ID |
| days | integer [ 1 .. 90 ] Default: 30 Number of days of event history to scan (1–90, default 30) |
{- "days": 30
}{- "would_fire_count": 5,
- "sample_leads": [
- "ld_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "ld_b2c3d4e5-f6a7-8901-bcde-f12345678901"
]
}Returns 24-hour delivery aggregate stats and the 10 most recent notification attempts for a surge trigger.
OU isolation: returns 404 when the trigger_id does not belong to the active OU, preventing cross-OU enumeration (ADR-0054).
| id required | string Surge trigger ID |
{- "delivered_24h": 0,
- "failed_24h": 3,
- "last_failure_at": "2026-05-12T01:12:13Z",
- "last_error": "connection timeout after 30s",
- "status": "red",
- "recent_attempts": [
- {
- "at": "2026-05-12T01:12:13Z",
- "outcome": "failed",
- "status": "retry_exhausted",
- "failure_stage": "dispatch",
- "error_excerpt": "connection timeout after 30s",
- "correlation_id": "corr-abc-123"
}
]
}Simulates a surge trigger against a single lead's event history and returns whether the trigger would have fired, how many times, and which specific time windows exceeded the threshold.
Unlike /preview (which scans all leads), this endpoint targets one lead and returns matched_windows for precise per-lead debugging and calibration.
No notifications are sent and the trigger state is not modified.
| id required | string Surge trigger ID |
| lead_id required | string The Lead ID to simulate against |
| days | integer [ 1 .. 90 ] Default: 30 Number of days of event history to scan (1–90, default 30) |
{- "lead_id": "ld_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "days": 30
}{- "would_fire": true,
- "total_matches": 2,
- "message": "Trigger would have fired 2 time(s) for this lead in the last 30 days",
- "matched_windows": [
- {
- "window_start": "2025-01-10T14:00:00Z",
- "window_end": "2025-01-10T16:00:00Z",
- "event_count": 7
}, - {
- "window_start": "2025-01-15T09:00:00Z",
- "window_end": "2025-01-15T11:00:00Z",
- "event_count": 6
}
]
}Returns surge events for the active organizational unit. Surge events are recorded each time a surge trigger fires.
| page | integer >= 1 Default: 1 |
| limit | integer [ 1 .. 500 ] Default: 50 |
| start | string <date-time> Start timestamp (RFC3339). |
| end | string <date-time> End timestamp (RFC3339). |
| channel | string Filter by surge channel (snapshot channel/source). |
[ ]| name | string |
| score_column | string Default: "total_score" |
| is_primary | boolean Default: false |
{- "name": "Marketing",
- "score_column": "total_score"
}{- "ruleset_id": "rs_marketing",
- "name": "Marketing",
- "score_column": "total_score"
}Evaluates a profile scoring rule against a specific lead without modifying production scores.
| lead_id required | string The lead to test the rule against |
required | object The profile rule configuration to evaluate |
{- "lead_id": "string",
- "rule": {
- "profile_property": "string",
- "condition": "equals",
- "comparison_value": "string",
- "weight": 0
}
}{- "matches": true,
- "reason": "string",
- "current_score": 0,
- "projected_score": 0,
- "matching_value": "string"
}| source_field required | string |
| profile_property required | string |
{- "source_field": "utm_source",
- "profile_property": "acquisition_source"
}{- "id": "pm_2",
- "source_field": "utm_source",
- "profile_property": "acquisition_source"
}| id required | string |
| source_field required | string |
| profile_property required | string |
{- "source_field": "string",
- "profile_property": "string"
}[- {
- "id": "string",
- "org_id": "string",
- "name": "string",
- "enabled": true,
- "is_primary": true,
- "score_floor_pct": 0.5,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| name required | string |
| enabled | boolean |
| is_primary | boolean Default: false |
{- "name": "string",
- "enabled": true,
- "is_primary": false
}{- "id": "string",
- "org_id": "string",
- "name": "string",
- "enabled": true,
- "is_primary": true,
- "score_floor_pct": 0.5,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string |
| name required | string |
| enabled | boolean |
| is_primary | boolean Default: false |
{- "name": "string",
- "enabled": true,
- "is_primary": false
}| id required | string |
[- {
- "id": "string",
- "ruleset_id": "string",
- "profile_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "half_life_days": 1,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}, - "ui_order": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| id required | string |
| profile_property required | string |
| condition required | string |
| comparison_value required | string |
| weight required | integer |
| ui_order | integer |
| rule_type | string Enum: "add_points" "hard_disqualify" Defaults to add_points when omitted. |
object or null Compound AND/OR condition group. Only valid when rule_type is hard_disqualify. |
{- "profile_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "ui_order": 0,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}
}{- "id": "string",
- "ruleset_id": "string",
- "profile_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "half_life_days": 1,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}, - "ui_order": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string |
| ruleId required | string |
| profile_property | string |
| condition | string |
| comparison_value | string |
| weight | integer |
| ui_order | integer |
| rule_type | string Enum: "add_points" "hard_disqualify" |
object or null Compound AND/OR condition group. Only valid when rule_type is hard_disqualify. |
{- "profile_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "ui_order": 0,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}
}Returns the audit log of all profile mapping changes — creates, updates, and deletes — for the active OU.
[- {
- "id": "string",
- "mapping_type": "string",
- "action": "created",
- "actor": "string",
- "old_value": { },
- "new_value": { },
- "created_at": "2019-08-24T14:15:22Z"
}
]Returns the number of leads that appear in both segments, plus counts for each segment individually.
| a required | string ID of the first segment |
| b required | string ID of the second segment |
{- "a_count": 0,
- "b_count": 0,
- "overlap_count": 0,
- "overlap_pct_a": 0,
- "overlap_pct_b": 0
}| name required | string |
| description | string |
| active | boolean |
{- "name": "string",
- "description": "string",
- "active": true
}{- "segment_id": "sg_marketing",
- "name": "Marketing Leads",
- "description": "Leads from marketing sources",
- "active": true
}| id required | string |
| name required | string |
| description | string |
| active | boolean |
{- "name": "string",
- "description": "string",
- "active": true
}| id required | string |
| include_disqualified | boolean Default: false When true, include disqualified leads in the count. Defaults to false (qualified-only). |
{- "count": 0
}| id required | string |
| page | integer >= 1 Default: 1 |
| limit | integer [ 1 .. 500 ] Default: 50 |
| include_disqualified | boolean Default: false When true, include disqualified leads. Defaults to false (qualified-only). |
[- {
- "org_id": "string",
- "lead_id": "string",
- "ruleset_id": "string",
- "score": 0,
- "last_event_at": "2019-08-24T14:15:22Z",
- "profile_scores": {
- "property1": 0,
- "property2": 0
}, - "ruleset_names": {
- "property1": "string",
- "property2": "string"
}, - "profile_primary_ruleset_name": "string",
- "engagement_scores": {
- "property1": 0,
- "property2": 0
}, - "engagement_primary_ruleset_name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "owner_name": "string",
- "account_id": "string",
- "engagement_level": "string",
- "profile_level": "string",
- "account_level": "string",
- "best_alias": "string"
}
]| id required | string |
[- {
- "rule_id": "string",
- "segment_id": "string",
- "org_id": "string",
- "rule_name": "string",
- "rule_type": "lead_metadata",
- "field_name": "string",
- "operator": "string",
- "value": "string",
- "event_type": "string",
- "logic_group": 0,
- "logic_op": "AND",
- "order_index": 0,
- "active": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}
]| id required | string |
| rule_name | string |
| rule_type required | string Enum: "lead_metadata" "event_metadata" |
| field_name required | string |
| operator required | string |
| value | string |
| event_type | string |
| logic_group | integer |
| logic_op | string Enum: "AND" "OR" |
| order_index | integer |
| active | boolean |
{- "rule_name": "string",
- "rule_type": "lead_metadata",
- "field_name": "string",
- "operator": "string",
- "value": "string",
- "event_type": "string",
- "logic_group": 0,
- "logic_op": "AND",
- "order_index": 0,
- "active": true
}{- "rule_id": "string",
- "segment_id": "string",
- "org_id": "string",
- "rule_name": "string",
- "rule_type": "lead_metadata",
- "field_name": "string",
- "operator": "string",
- "value": "string",
- "event_type": "string",
- "logic_group": 0,
- "logic_op": "AND",
- "order_index": 0,
- "active": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| ruleId required | string |
| rule_name | string |
| rule_type | string Enum: "lead_metadata" "event_metadata" |
| field_name | string |
| operator | string |
| value | string |
| event_type | string |
| logic_group | integer |
| logic_op | string Enum: "AND" "OR" |
| order_index | integer |
| active | boolean |
{- "rule_name": "string",
- "rule_type": "lead_metadata",
- "field_name": "string",
- "operator": "string",
- "value": "string",
- "event_type": "string",
- "logic_group": 0,
- "logic_op": "AND",
- "order_index": 0,
- "active": true
}| inactive_for required | integer Duration amount |
| unit required | string Enum: "days" "hours" "weeks" |
| decrease required | integer Score decrease amount |
{- "inactive_for": 0,
- "unit": "days",
- "decrease": 0
}{- "decay_id": "dc_inactive30d",
- "inactive_for": 30,
- "unit": "days",
- "decrease": 25
}| id required | string |
| inactive_for | integer |
| unit | string Enum: "days" "hours" "weeks" |
| decrease | integer |
{- "inactive_for": 0,
- "unit": "days",
- "decrease": 0
}Lists configured inorganic activity filters used to flag bot-like activity in the active OU.
[- {
- "filter_id": "string",
- "event_type": "string",
- "count_threshold": 0,
- "time_window_ms": 0,
- "group_events": true,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}
]| event_type required | string |
| count_threshold required | integer |
| time_window_ms required | integer |
| group_events | boolean |
{- "event_type": "string",
- "count_threshold": 0,
- "time_window_ms": 0,
- "group_events": true
}{- "filter_id": "string",
- "event_type": "string",
- "count_threshold": 0,
- "time_window_ms": 0,
- "group_events": true,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| event_type | string |
| count_threshold | integer |
| time_window_ms | integer |
| group_events | boolean |
{- "event_type": "string",
- "count_threshold": 0,
- "time_window_ms": 0,
- "group_events": true
}Attribute based filters suppress engagement events whose metadata matches key/value conditions. Evaluated before velocity based filters.
Returns all metadata attribute filters for the active OU, sorted enabled-first then newest-first.
[- {
- "id": "string",
- "unit_id": "string",
- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true,
- "suppressed_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}
]| name required | string Human-readable label for the filter |
| event_type | string Scope to a specific event type. Empty string matches all types. |
Array of objects (MetadataAttributeFilterCondition) | |
| enabled | boolean Default: true |
{- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true
}{- "id": "string",
- "unit_id": "string",
- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true,
- "suppressed_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}Runs the provided conditions against existing events and returns how many would be suppressed. Does not persist any changes.
| event_type | string Scope preview to a specific event type. Omit for all types. |
required | Array of objects (MetadataAttributeFilterCondition) |
{- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
]
}{- "count": 0
}| id required | string |
{- "id": "string",
- "unit_id": "string",
- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true,
- "suppressed_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| name required | string |
| event_type | string |
Array of objects (MetadataAttributeFilterCondition) | |
| enabled | boolean |
{- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true
}{- "id": "string",
- "unit_id": "string",
- "name": "string",
- "event_type": "string",
- "conditions": [
- {
- "key": "string",
- "operator": "equals",
- "value": "string"
}
], - "enabled": true,
- "suppressed_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}Lists pattern triggers (including frequency counts) for the active OU.
[- {
- "trigger_id": "string",
- "name": "string",
- "description": "string",
- "active": true,
- "window_seconds": 0,
- "conditions": [
- {
- "type": "count",
- "event_type": "string",
- "count": 0,
- "operator": "gte"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| trigger_id | string |
| name | string |
| description | string |
| active | boolean |
| window_seconds | integer |
Array of objects | |
| webhook_url | string |
| emails | Array of strings <email> [ items <email > ] |
| created_at | string <date-time> |
| updated_at | string <date-time> |
{- "trigger_id": "string",
- "name": "string",
- "description": "string",
- "active": true,
- "window_seconds": 0,
- "conditions": [
- {
- "type": "count",
- "event_type": "string",
- "count": 0,
- "operator": "gte"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}{- "trigger_id": "string",
- "name": "string",
- "description": "string",
- "active": true,
- "window_seconds": 0,
- "conditions": [
- {
- "type": "count",
- "event_type": "string",
- "count": 0,
- "operator": "gte"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string |
| trigger_id | string |
| name | string |
| description | string |
| active | boolean |
| window_seconds | integer |
Array of objects | |
| webhook_url | string |
| emails | Array of strings <email> [ items <email > ] |
| created_at | string <date-time> |
| updated_at | string <date-time> |
{- "trigger_id": "string",
- "name": "string",
- "description": "string",
- "active": true,
- "window_seconds": 0,
- "conditions": [
- {
- "type": "count",
- "event_type": "string",
- "count": 0,
- "operator": "gte"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Returns a paginated list of notification failure records for the active Organizational Unit. Results are ordered by last_attempt_at DESC, id DESC. Use next_cursor to fetch subsequent pages. All filters are optional; omitting them returns the last 7 days of failures.
| channel_id | string <uuid> Filter to failures for a specific notification channel. |
| trigger_id | string <uuid> Filter to failures associated with a specific trigger. |
| trigger_type | string Enum: "milestone" "sequence" "surge" Filter to failures for a specific trigger type. |
| status | string Comma-separated list of statuses to include. Valid values: enqueue_failed, retry_exhausted, terminal_4xx, delivered. |
| failure_stage | string Enum: "enqueue" "dispatch" "surge_webhook" "probe" Filter to failures at a specific pipeline stage. |
| since | string <date-time> RFC3339 timestamp. Only return failures where last_attempt_at >= since. Defaults to 7 days ago when omitted. |
| limit | integer [ 1 .. 200 ] Default: 50 Page size. Maximum 200. Returns 400 if exceeded. |
| cursor | string Opaque pagination cursor returned as next_cursor from a previous response. |
{- "items": [
- {
- "id": 0,
- "channel": "string",
- "trigger_type": "milestone",
- "trigger_id": "5727dbbb-3b26-4abe-aec6-181eabbdb21c",
- "status": "enqueue_failed",
- "failure_stage": "enqueue",
- "last_error": "string",
- "attempts": 0,
- "correlation_id": "string",
- "received_at": "2019-08-24T14:15:22Z",
- "last_attempt_at": "2019-08-24T14:15:22Z"
}
], - "next_cursor": "string",
- "total_count": 0
}Returns all saved notification channels for the active Organizational Unit. Channels can be referenced when creating Milestone or Sequence Triggers.
[- {
- "id": "string",
- "unit_id": "string",
- "name": "string",
- "type": "slack",
- "config": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| name required | string Display name for the channel |
| type required | string Enum: "slack" "teams" "webhook" "email" |
required | object Type-specific configuration fields |
{- "name": "string",
- "type": "slack",
- "config": {
- "property1": "string",
- "property2": "string"
}
}| id required | string |
| name | string |
| type | string Enum: "slack" "teams" "webhook" "email" |
object |
{- "name": "string",
- "type": "slack",
- "config": {
- "property1": "string",
- "property2": "string"
}
}Returns a 24-hour health summary for a single notification channel. The channel must belong to the caller's active Organizational Unit; a missing or cross-OU channel returns 404 to avoid existence leaking. delivered_24h limitation (Sprint-3.5): This field is always 0 until Sprint-3.5b adds a success counter to the worker dispatch path. As a result, status green (delivered > 0, failed = 0) and amber (failed > 0, failed < delivered) are unreachable until that counter exists. The meaningful states today are gray (no failures recorded) and red (at least one failure recorded with no tracked deliveries). Once Sprint-3.5b ships, delivered_24h will reflect actual successful dispatches and all four statuses become reachable.
| id required | string <uuid> Notification channel UUID |
{- "delivered_24h": 0,
- "failed_24h": 0,
- "last_failure_at": "2019-08-24T14:15:22Z",
- "last_error": "string",
- "status": "green"
}Lists milestone triggers configured for the active OU.
[- {
- "trigger_id": "string",
- "org_id": "string",
- "event_type": "string",
- "score_threshold": 0,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}
]| event_type required | string |
| score_threshold required | integer |
| webhook_url | string |
| emails | Array of strings <email> [ items <email > ] |
| email_subject | string |
| email_preheader | string |
| email_message | string |
{- "event_type": "string",
- "score_threshold": 0,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string"
}{- "trigger_id": "string",
- "org_id": "string",
- "event_type": "string",
- "score_threshold": 0,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| event_type | string |
| score_threshold | integer |
| webhook_url | string |
| emails | Array of strings <email> [ items <email > ] |
| email_subject | string |
| email_preheader | string |
| email_message | string |
{- "event_type": "string",
- "score_threshold": 0,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string"
}Returns 24-hour delivery aggregate stats and the 10 most recent notification attempts for a milestone trigger.
OU isolation: returns 404 when the trigger_id does not belong to the active OU, preventing cross-OU enumeration (ADR-0054).
| id required | string Milestone trigger ID |
{- "delivered_24h": 0,
- "failed_24h": 3,
- "last_failure_at": "2026-05-12T01:12:13Z",
- "last_error": "connection timeout after 30s",
- "status": "red",
- "recent_attempts": [
- {
- "at": "2026-05-12T01:12:13Z",
- "outcome": "failed",
- "status": "retry_exhausted",
- "failure_stage": "dispatch",
- "error_excerpt": "connection timeout after 30s",
- "correlation_id": "corr-abc-123"
}
]
}Test a milestone trigger against a specific lead or scan historical data. Returns whether the trigger would fire and which leads match.
| id required | string |
| lead_id | string Specific lead to test (optional) |
| days | integer Default: 30 Days to look back |
{- "lead_id": "string",
- "days": 30
}{- "would_fire": true,
- "matched_leads": [
- "string"
], - "total_matches": 0,
- "message": "string"
}Lists time- or order-based sequence triggers for the active OU.
[- {
- "trigger_id": "string",
- "org_id": "string",
- "unit_id": "string",
- "name": "string",
- "event_steps": [
- {
- "event_type": "string",
- "attribute_filters": [
- {
- "field": "string",
- "operator": "equals",
- "value": "string"
}
]
}
], - "window_seconds": 0,
- "window_unit": "seconds",
- "ordered": true,
- "fire_mode": "once",
- "profile_filters": [
- {
- "field": "engagement_level",
- "operator": "eq",
- "value": "string"
}
], - "lead_attribute_filters": [
- {
- "field": "string",
- "operator": "equals",
- "value": "string"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string",
- "slack_target_kind": "channel",
- "slack_target_id": "string",
- "teams_target_kind": "channel",
- "teams_target_id": "string",
- "hubspot_sync": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}
]| event_types required | Array of strings |
| window_seconds required | integer |
| window_unit required | string Enum: "seconds" "minutes" "hours" |
| ordered | boolean |
| webhook_url required | string |
| emails | Array of strings <email> [ items <email > ] |
| email_subject | string |
| email_preheader | string |
| email_message | string |
{- "event_types": [
- "string"
], - "window_seconds": 0,
- "window_unit": "seconds",
- "ordered": true,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string"
}{- "trigger_id": "string",
- "org_id": "string",
- "unit_id": "string",
- "name": "string",
- "event_steps": [
- {
- "event_type": "string",
- "attribute_filters": [
- {
- "field": "string",
- "operator": "equals",
- "value": "string"
}
]
}
], - "window_seconds": 0,
- "window_unit": "seconds",
- "ordered": true,
- "fire_mode": "once",
- "profile_filters": [
- {
- "field": "engagement_level",
- "operator": "eq",
- "value": "string"
}
], - "lead_attribute_filters": [
- {
- "field": "string",
- "operator": "equals",
- "value": "string"
}
], - "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string",
- "slack_target_kind": "channel",
- "slack_target_id": "string",
- "teams_target_kind": "channel",
- "teams_target_id": "string",
- "hubspot_sync": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| event_types | Array of strings |
| window_seconds | integer |
| window_unit | string Enum: "seconds" "minutes" "hours" |
| ordered | boolean |
| webhook_url | string |
| emails | Array of strings <email> [ items <email > ] |
| email_subject | string |
| email_preheader | string |
| email_message | string |
{- "event_types": [
- "string"
], - "window_seconds": 0,
- "window_unit": "seconds",
- "ordered": true,
- "webhook_url": "string",
- "emails": [
- "user@example.com"
], - "email_subject": "string",
- "email_preheader": "string",
- "email_message": "string"
}Returns 24-hour delivery aggregate stats and the 10 most recent notification attempts for a sequence trigger.
OU isolation: returns 404 when the trigger_id does not belong to the active OU, preventing cross-OU enumeration (ADR-0054).
| id required | string Sequence trigger ID |
{- "delivered_24h": 0,
- "failed_24h": 3,
- "last_failure_at": "2026-05-12T01:12:13Z",
- "last_error": "connection timeout after 30s",
- "status": "red",
- "recent_attempts": [
- {
- "at": "2026-05-12T01:12:13Z",
- "outcome": "failed",
- "status": "retry_exhausted",
- "failure_stage": "dispatch",
- "error_excerpt": "connection timeout after 30s",
- "correlation_id": "corr-abc-123"
}
]
}Test a sequence trigger against a specific lead or scan historical data. Returns whether the trigger would fire and which leads match.
| id required | string |
| lead_id | string Specific lead to test (optional) |
| days | integer Default: 30 Days to look back |
{- "lead_id": "string",
- "days": 30
}{- "would_fire": true,
- "matched_leads": [
- "string"
], - "total_matches": 0,
- "message": "string"
}| id required | string |
| name required | string |
{- "name": "string"
}{- "unit_id": "string",
- "name": "string",
- "slug": "string"
}Validates membership and sets the activeOu cookie. Returns OU headers for convenience.
| ouId required | string The unit_id to activate for the current session |
{- "ouId": "string"
}Lists members of the current organization. Results are organization-scoped.
[- {
- "org_member_id": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "user@example.com",
- "role": "string"
}
]| first_name required | string |
| last_name required | string |
| email required | string <email> |
| password required | string <password> |
| role required | string |
{- "first_name": "string",
- "last_name": "string",
- "email": "user@example.com",
- "password": "pa$$word",
- "role": "string"
}{- "org_member_id": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "user@example.com",
- "role": "string"
}| id required | string |
| first_name | string |
| last_name | string |
string <email> | |
| role | string |
{- "first_name": "string",
- "last_name": "string",
- "email": "user@example.com",
- "role": "string"
}Set a member's Slack user identifier directly, bypassing the email-based sync. Use this when a member's kenbun email differs from their Slack workspace email. Admin role required. Tenant isolation is enforced — admins cannot set a Slack identifier for a member in a different organization.
| org_member_id required | string Identifier of the target member. |
| slack_user_id required | string^U[A-Z0-9]+$ Slack user identifier. Must begin with U followed by uppercase letters and digits. |
{- "slack_user_id": "U012AB3CD"
}Lists members assigned to the specified OU with OU-scoped roles. Requires caller to be a member of that OU.
| id required | string OU ID (unit_id) |
[- {
- "org_member_id": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "user@example.com",
- "role": "Owner"
}
]Assigns a member to the specified OU with a role. Idempotent. Requires OU role Owner or Operator.
| id required | string OU ID (unit_id) |
| org_member_id required | string |
| role | string Default: "Viewer" Enum: "Owner" "Operator" "Viewer" |
{- "org_member_id": "string",
- "role": "Owner"
}| id required | string |
| memberId required | string |
| role required | string Enum: "Owner" "Operator" "Viewer" |
{- "role": "Owner"
}Returns whether rate limiting is enabled, the mode, keying policy, computed key for this caller, and numeric limits.
{- "enabled": true,
- "mode": "observe",
- "key_by": "org",
- "key": "string",
- "rps": 0,
- "burst": 0,
- "stage": "string"
}Returns the calling user's notification preferences for the active Organizational Unit. Always lists all four canonical event types; any event type without a stored row defaults to muted=false. The slack_user_id field is masked for display (e.g. "U12•••XYZ") or null when the user is not yet mapped.
{- "notifications_enabled": true,
- "slack_user_id": "string",
- "prefs": [
- {
- "event_type": "milestone.entered",
- "muted": true
}
]
}Update the master toggle, the per-event-type mute settings, or both. Both top-level fields are optional;
omitted fields are left unchanged. Each entry in prefs must reference a canonical event_type, otherwise the request is rejected with 400.
| notifications_enabled | boolean Master toggle. |
Array of objects |
{- "notifications_enabled": true,
- "prefs": [
- {
- "event_type": "milestone.entered",
- "muted": true
}
]
}{- "status": "ok"
}| name required | string <= 50 characters Human-friendly label for this credential (1–50 chars) |
{- "name": "string"
}{- "secret_id": "string",
- "client_id": "string",
- "client_secret": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z"
}SSE stream of score updates, surge events, and newly ingested events.
OU scoping:
ouId as a query param to receive only events for that OU.activeOu cookie.Note: This endpoint is currently unauthenticated.
| ouId | string Organization Unit (OU) ID to scope the stream. |
event: score_update data: {"lead_id":"ld_123","delta":5}
Returns current-month event usage, billing limits, and overage information for the organization.
{- "monthly_events": 0,
- "free_tier_limit": 0,
- "overage_rate_cents": 0,
- "overage_unit": 0,
- "overage": true,
- "billing_cycle_start": "2019-08-24T14:15:22Z",
- "billing_cycle_end": "2019-08-24T14:15:22Z",
- "org_id": "string",
- "org_name": "string",
- "subscription_status": "active",
- "trial_ends_at": "2019-08-24T14:15:22Z"
}Receives subscription lifecycle events from kenbun's billing provider. This endpoint is called automatically by the billing system — not by API clients. Processes subscription.created, subscription.updated, subscriptionItem.freeTrialEnding, and payment_attempt events. All requests are authenticated using a signed-payload signature, which kenbun verifies on every incoming request.
| type | string Event type (e.g., subscription.created, subscription.updated) |
| data | object Event payload (varies by type) |
{- "type": "string",
- "data": { }
}{- "received": true
}Returns aggregated surge metrics for the specified organization unit within a time range. Requires authentication and an active organization; OU membership is enforced.
| ouId required | string Organization Unit ID to scope the results. |
| start required | string <date-time> Start of the time range (RFC3339). |
| end required | string <date-time> End of the time range (RFC3339). |
| interval | string Enum: "15m" "1h" "1d" Aggregation interval. Defaults to |
| channel | string Optional channel filter (e.g., 'web', 'email', 'slack'). |
{- "ou_id": "string",
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z",
- "interval": "15m",
- "totals": {
- "surges": 0,
- "unique_leads": 0
}, - "peak": {
- "ts": "2019-08-24T14:15:22Z",
- "count": 0
}, - "channels": [
- {
- "channel": "string",
- "count": 0
}
], - "series": [
- {
- "ts": "2019-08-24T14:15:22Z",
- "total": 0,
- "by_channel": {
- "property1": 0,
- "property2": 0
}
}
]
}Runs account/profile mapping and recalculates profile scores for all leads in the active OU.
{- "leads_processed": 0,
- "accounts_linked": 0,
- "accounts_created": 0,
- "profile_scores_updated": 0
}Adds or corrects the accountId in event metadata by joining each event's lead to its associated account within the active OU. No-op for events that already have accountId.
{- "events_scanned": 0,
- "events_updated": 0,
- "leads_without_account": 0
}Reads all leads in the active OU and applies the currently configured profile field mappings to populate lead metadata. Respects each mapping's update behavior setting.
{- "leads_processed": 0,
- "leads_updated": 0
}Returns recent audit log entries for the active OU with optional filters and sorting.
| limit | integer [ 1 .. 500 ] Max rows to return (default 100; max 500) |
| offset | integer >= 0 Number of rows to skip (for pagination) |
| search | string Search across user_email, path, and IP address |
| method | string Enum: "GET" "POST" "PUT" "PATCH" "DELETE" Filter by HTTP method |
| status_min | integer Minimum status code (inclusive) |
| status_max | integer Maximum status code (inclusive) |
| user_email | string Filter by exact user email |
| sort_by | string Default: "created_at" Enum: "created_at" "user_email" "method" "path" "status" "ip" "latency_ms" Column to sort by |
| sort_order | string Default: "DESC" Enum: "ASC" "DESC" Sort order (ascending or descending) |
{- "items": [
- {
- "id": "string",
- "org_id": "string",
- "unit_id": "string",
- "user_sub": "string",
- "user_email": "string",
- "method": "string",
- "path": "string",
- "status": 0,
- "ip": "string",
- "user_agent": "string",
- "latency_ms": 0,
- "request_id": "string",
- "created_at": "2019-08-24T14:15:22Z"
}
], - "limit": 0,
- "offset": 0
}Sets the Slack app client ID and client secret for the current organization.
| client_id required | string |
| client_secret required | string |
{- "client_id": "string",
- "client_secret": "string"
}Fetches a public website and returns proposed Page View scoring rules based on URL pattern categorization. Tries sitemap.xml first, falls back to homepage crawl + one level deep. Returns one proposed rule per intent category found on the site. Used by the Quick Start wizard to bootstrap scoring configuration.
| url required | string Public website URL to analyze. Scheme is added automatically if omitted. |
{
}{- "domain": "example.com",
- "fetched_url": "string",
- "page_count": 0,
- "skipped_urls": 0,
- "source": "sitemap",
- "categories": [
- {
- "category": "High Intent - Pricing",
- "pattern": "pricing",
- "urls": [
- "string"
], - "suggested_weight": 0,
- "icon": "string"
}
], - "proposed_rules": [
- {
- "event_type": "Page View",
- "weight": 0,
- "label": "string",
- "icon": "string",
- "attribute_filters": [
- {
- "field": "path",
- "operator": "contains",
- "value": "pricing"
}
]
}
]
}Generate a new Personal Access Token (PAT) for the authenticated user.
PATs authenticate API and MCP requests as the user with their permissions.
The full token value (beginning with kbn_pat_) is returned once in this response.
Store it securely — it cannot be retrieved again.
| name required | string [ 1 .. 100 ] characters Descriptive label for the token (1–100 characters) |
| expires_at | string or null <date-time> Optional expiry date and time in RFC 3339 format. If omitted, the token does not expire. Must be a future timestamp. |
{- "name": "MCP Server - Laptop",
- "expires_at": "2027-01-01T00:00:00Z"
}{- "id": "string",
- "name": "string",
- "token": "kbn_pat_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
- "token_prefix": "kbn_pat_a1b2c3d4",
- "created_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z"
}Returns all Personal Access Tokens for the authenticated user. Token values are never included in this response — only metadata for managing tokens.
[- {
- "id": "string",
- "name": "string",
- "token_prefix": "kbn_pat_a1b2c3d4",
- "created_at": "2019-08-24T14:15:22Z",
- "last_used_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "revoked_at": "2019-08-24T14:15:22Z"
}
]Revokes a Personal Access Token. Once revoked, any system using that token will immediately lose access. This action cannot be undone. Users can only revoke their own tokens.
| id required | string The token ID (from POST /settings/tokens or GET /settings/tokens) |
Returns organization event types with hidden flag and per-OU event counts.
[- {
- "name": "string",
- "hidden": true,
- "max_processing_scope": "observe",
- "ou_event_count": 0,
- "protected": true,
- "deletable": true
}
]| eventType required | string |
| hidden | boolean |
| max_processing_scope | string Enum: "observe" "decide" "activate" Ceiling for event processing in this OU; does not imply execution. |
{- "hidden": true,
- "max_processing_scope": "observe"
}Returns whether the active OU is connected to a Slack workspace and basic metadata.
{- "connected": true,
- "team_name": "string",
- "team_id": "string",
- "bot_user_id": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "default_target_kind": "channel",
- "default_target_id": "string",
- "authorize_url": "string"
}Proxies Slack conversations.list and returns the upstream response. Requires the OU to be connected to Slack.
| types | string Example: types=public_channel,private_channel |
{- "ok": true,
- "channels": [
- {
- "id": "string",
- "name": "string",
- "is_private": true
}
], - "response_metadata": {
- "next_cursor": "string"
}
}Proxies Slack users.list and returns the upstream response. Requires the OU to be connected to Slack.
{- "ok": true,
- "members": [
- {
- "id": "string",
- "name": "string"
}
], - "response_metadata": {
- "next_cursor": "string"
}
}Persists the default Slack target (channel or user) for notifications.
| kind required | string Enum: "channel" "user" |
| id required | string |
{- "kind": "channel",
- "id": "string"
}Sends a simple test message to the provided channel or user for the active OU. If kind=user, opens a DM first.
| kind required | string Enum: "channel" "user" |
| id required | string |
| text | string Optional custom message |
{- "kind": "channel",
- "id": "string",
- "text": "string"
}{- "message": "string"
}Returns whether the OU has opted in to a Slack post when a scoring ruleset is published (ADR-0050 Phase 1.5.4). Default false. When the OU is not connected to Slack, returns { enabled: false } so the UI can render a consistent empty state.
{- "enabled": true
}Persists the per-OU opt-in for posting to Slack on ruleset publish. Returns 404 when the OU has no Slack connection — connect Slack first.
| enabled required | boolean |
{- "enabled": true
}{- "enabled": true
}Returns the active OU's conversion definition, cold-start calibration state, and (when a HubSpot connection exists with a recorded sync time) HubSpot sync freshness information.
The hubspot_sync_freshness key is omitted entirely when no HubSpot
connection is configured or when last_sync_at has never been recorded.
cold_start_state.eligible is true when conversions_observed >= 30, which
is the minimum signal required for the calibration engine to run.
{- "definition": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "org_id": "string",
- "unit_id": "5becc822-b69e-4e66-a762-ad8e868dcab6",
- "conversion_type": "closed_won",
- "event_type_id": 0,
- "deal_stages": [
- "string"
], - "engagement_persistence_days": 7,
- "lookback_days": 30,
- "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "cold_start_state": {
- "leads_scored": 0,
- "conversions_observed": 0,
- "conversions_required": 30,
- "eligible": true
}, - "hubspot_sync_freshness": {
- "last_synced_at": "2019-08-24T14:15:22Z",
- "hours_since_sync": 0.1,
- "stale": true
}
}Creates or replaces the active OU's conversion definition. Only one definition per OU is allowed; calling PUT again replaces the existing row.
Validation rules:
conversion_type must be one of: closed_won, deal_stage_reached,
event_type_match, engagement_persistence, manual_label.sales_disposition is rejected until P1 closed-loop disposition feedback ships.closed_won / deal_stage_reached: deal_stages must be non-empty.
If HubSpot pipeline stages have been synced, each stage ID is validated against
the known list. If no stages have been synced yet, validation is skipped.event_type_match: event_type_id must reference an existing event type
for this organisation.engagement_persistence_days must be 7–60 (default 14).lookback_days must be 30–365 (default 90).| conversion_type required | string Enum: "closed_won" "deal_stage_reached" "event_type_match" "engagement_persistence" "manual_label" |
| deal_stages | Array of strings Required for closed_won / deal_stage_reached. |
| event_type_id | integer Required for event_type_match. Must reference an existing event type for this organisation. |
| engagement_persistence_days | integer [ 7 .. 60 ] Default: 14 Inactivity window in days (engagement_persistence type only). |
| lookback_days | integer [ 30 .. 365 ] Default: 90 Historical window for conversion counting. |
{- "conversion_type": "closed_won",
- "deal_stages": [
- "string"
], - "event_type_id": 0,
- "engagement_persistence_days": 14,
- "lookback_days": 90
}{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "org_id": "string",
- "unit_id": "5becc822-b69e-4e66-a762-ad8e868dcab6",
- "conversion_type": "closed_won",
- "event_type_id": 0,
- "deal_stages": [
- "string"
], - "engagement_persistence_days": 7,
- "lookback_days": 30,
- "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Returns the OU-scoped session-based surge multiplier policy for the active OU. If none exists, returns Standard defaults.
{- "org_id": "string",
- "unit_id": "string",
- "mode": "off",
- "bands": [
- {
- "start_min": 0,
- "end_min": 1,
- "multiplier": 1
}
], - "idle_reset_seconds": 1,
- "multiplier_cap": 1
}Creates or updates the session-based surge multiplier policy for the active OU.
| mode | string Enum: "off" "standard" "gentle" "custom" |
Array of objects | |
| idle_reset_seconds | integer >= 1 |
| multiplier_cap | number [ 1 .. 3 ] |
{- "mode": "off",
- "bands": [
- {
- "start_min": 0,
- "end_min": 1,
- "multiplier": 1
}
], - "idle_reset_seconds": 1,
- "multiplier_cap": 1
}Returns the total number of confirmed members in the active Organizational Unit and how many of them have a Slack user identifier on file. Used by the trigger configuration UI to render the "X of Y mapped" status pill next to the "Notify the Lead Owner" option. Available to any authenticated member of the active Organizational Unit (admin role not required).
{- "total": 0,
- "mapped": 0
}Looks up every confirmed member in the active Organizational Unit by email in the connected Slack workspace and stores any matches. Members already mapped are skipped. The endpoint blocks until the sync completes and returns a summary. Admin role required.
{- "members_total": 0,
- "matched": 0,
- "no_match": 0,
- "errors": 0
}Unauthenticated endpoints that serve publicly shareable content. These endpoints do not require an API key or session cookie.
Returns the score explanation for a previously shared link. No authentication is required. Returns 410 if the link has expired, 404 if the token does not exist.
| token required | string Share token returned by POST /leads/{id}/share-explain |
{- "lead_name": "string",
- "score": 0,
- "top_drivers": [
- {
- "rule_id": "string",
- "event_type": "string",
- "count": 0,
- "weight": 0,
- "total": 0,
- "filter_label": "string",
- "half_life_days": 0,
- "most_recent_at": "2019-08-24T14:15:22Z"
}
], - "snapshot": [
- {
- "event_type": "string",
- "weight": 0
}
], - "decay_applied": 0,
- "range_hours": 0
}HubSpot integration endpoints for connecting kenbun to your HubSpot CRM, syncing contacts and deals, managing engagement history preferences, and monitoring sync health. All endpoints require an authenticated session and an active Organizational Unit.
Updates which HubSpot engagement types (emails, calls, meetings, notes, tasks) are synced for the active Organizational Unit. Optionally marks the connection as including engagement history imports.
Changes take effect for future syncs. To trigger an immediate import of past
engagement activity, use POST /settings/ou/hubspot/backfill with
include_engagement_history: true.
| engagement_types required | Array of strings Items Enum: "emails" "calls" "meetings" "notes" "tasks" Engagement types to sync going forward. Pass an empty array to disable all types. |
| include_engagement_history | boolean When true, marks that engagement history imports are enabled for this connection. |
{- "engagement_types": [
- "emails",
- "calls",
- "meetings"
], - "include_engagement_history": false
}{- "engagement_types": [
- "string"
], - "include_engagement_history": true
}Returns the current engagement history sync configuration and status for the active Organizational Unit. Use this to check which engagement types are enabled and when the last engagement import completed.
{- "engagement_types": [
- "emails",
- "calls",
- "meetings"
], - "include_engagement_history": true,
- "engagement_history_synced": true,
- "engagement_history_synced_at": "2019-08-24T14:15:22Z"
}Queues a background import of historical HubSpot data for the active Organizational Unit. Supports importing contacts, engagement history, or both in a single request.
Backwards compatibility: Sending no request body (or omitting include_contacts)
defaults to importing contacts only — matching the original behavior of this endpoint.
All queued jobs run in the background. For large datasets (10,000+ records), imports may take several hours. Check sync status to monitor progress.
| include_contacts | boolean Whether to import historical contacts. Defaults to |
| include_engagement_history | boolean Whether to import historical engagement activity (emails, calls, meetings, notes, tasks). |
| engagement_types | Array of strings Items Enum: "emails" "calls" "meetings" "notes" "tasks" Which engagement types to import. Only used when |
| force | boolean When |
{- "include_contacts": true,
- "include_engagement_history": true,
- "engagement_types": [
- "emails",
- "calls",
- "meetings"
], - "force": false
}{- "status": "queued",
- "message": "Historical import started",
- "queued": [
- "contacts",
- "engagements"
]
}Returns the current HubSpot connection state for the active Organizational Unit, including which OAuth app is brokering the connection.
The app_mode field tells callers whether the connection is using the
kenbun-managed shared OAuth app (the default for most customers) or a
customer-supplied OAuth app (Bring Your Own App, enterprise opt-in):
shared — connection uses the kenbun-managed OAuth app. No customer
credentials are stored on the connection row.byo — connection uses customer-supplied OAuth credentials saved via
POST /settings/ou/hubspot/credentials.unconfigured — neither shared OAuth credentials nor customer-supplied
credentials are available. The Connect button is not usable until one
source is configured.{- "connected": true,
- "app_mode": "shared",
- "has_credentials": true,
- "portal_id": "string",
- "last_synced_at": "2019-08-24T14:15:22Z"
}Builds the HubSpot authorization URL for the active Organizational Unit and returns it to the caller, who should redirect the browser to that URL. After the user consents in HubSpot, HubSpot redirects back to the kenbun OAuth callback to complete the handshake.
The endpoint uses whichever OAuth app is configured for the active OU:
app_mode: byo), the URL is built using those credentials.app_mode: shared).If neither source is available, the endpoint returns 412 Precondition Failed so the UI can prompt the customer to either contact support or configure Bring Your Own App credentials.
{- "app_mode": "shared"
}Stores Client ID and Client Secret for a customer-owned HubSpot OAuth
app on the active Organizational Unit's connection row. After saving,
subsequent calls to POST /settings/ou/hubspot/oauth/initiate build
the authorization URL using these credentials, putting the connection
into app_mode: byo.
Most customers do not need this endpoint. It exists for enterprise teams that require dedicated rate limits, customer-branded consent screens, or self-hosted compliance posture. The default Connect HubSpot flow uses the kenbun-managed shared app and does not require any credentials.
| client_id required | string HubSpot OAuth app Client ID from your HubSpot Developer Account. |
| client_secret required | string HubSpot OAuth app Client Secret. Stored encrypted at rest. |
{- "client_id": "string",
- "client_secret": "string"
}{- "status": "saved",
- "app_mode": "byo"
}Removes the customer-supplied Client ID and Client Secret from the
active Organizational Unit's HubSpot connection, reverting it to the
kenbun-managed shared OAuth app. After this call, the connection's
app_mode becomes shared and the customer must re-authorize via
POST /settings/ou/hubspot/oauth/initiate so HubSpot issues new
tokens against the shared app.
Previously synced contacts, deals, engagement history, and scores are preserved. Only the OAuth app routing changes.
{- "status": "cleared",
- "app_mode": "shared"
}Setup status endpoint used by the guided setup checklist on the Overview dashboard. Completion is auto-detected from real OU-scoped data — no manual state to manage.
Returns the completion status of each guided setup step for the active Organizational Unit. Completion is auto-detected from real data — no separate flag to set. Steps: connect an integration, create a scoring rule, set up engagement levels. Also accessible at the legacy path /onboarding-status (same handler, same response).
{- "steps": [
- {
- "id": "connect_integration",
- "label": "Connect an integration",
- "completed": true,
- "action_path": "/settings/integrations"
}, - {
- "id": "create_scoring_rules",
- "label": "Create your first scoring rule",
- "completed": false,
- "action_path": "/configure/scoring/engagement"
}, - {
- "id": "set_engagement_levels",
- "label": "Set up engagement levels",
- "completed": false,
- "action_path": "/configure/levels/engagement"
}
], - "all_complete": false,
- "completed_count": 1,
- "total_count": 3
}Phase 2 Feature (ABM Required)
Account-based marketing endpoints require abm_enabled: true in organization scoring settings.
These endpoints return 403 Forbidden if ABM is not enabled for your organization.
Contact your account manager for access.
Returns the first account matching the provided domain or company name. Domain is checked first; name is used as a fallback when domain is not provided or yields no match. Returns null when no matching account is found. OU-scoped to the active Organizational Unit.
| domain | string Domain to search for (e.g., acme.com). Checked before name. |
| name | string Exact company name to search for. Used as fallback when domain is not provided or returns no match. |
{- "account_id": "acct_abc123",
- "name": "Acme Corporation",
- "domain": "acme.com"
}Returns accounts whose names fuzzy-match the given query, ranked by similarity score. Uses a combination of string similarity algorithms (Jaro-Winkler and Token Set Ratio) to find close matches. Returns up to 5 results above a 0.6 similarity threshold. OU-scoped to the active Organizational Unit.
| name required | string Company name to search for (e.g., "Salesforce LLC"). |
{- "matches": [
- {
- "account_id": "acct_abc123",
- "name": "Salesforce",
- "score": 0.92
}, - {
- "account_id": "acct_def456",
- "name": "Salesforce.com Inc",
- "score": 0.78
}
]
}Returns a list of accounts for the active OU by aggregating leads joined with accounts and lead scores. Fields include top_score (max lead score within the account), leads_count, owner_name (from the top-scoring lead), and surging (true if any lead in the account surged in the last 24 hours).
| page | integer >= 1 Default: 1 |
| limit | integer [ 1 .. 500 ] Default: 50 |
| range | string Enum: "all" "today" "yesterday" "last_24h" "last_7d" "last_30d" "last_90d" Filter accounts by created_at using a named range. |
| search | string Search by account name or domain. |
| intent_level | string Enum: "all" "low" "medium" "high" Filter by intent level. |
| sort_by | string Enum: "name" "score" "engagement" "last_activity" "owner_name" Field to sort by. |
| sort_order | string Default: "desc" Enum: "asc" "desc" Sort direction. |
| account_level | string Filter by account level name (e.g., "Target", "Qualified"). |
| min_score | integer Minimum account score. |
| owner_name | string Filter by owner display name (partial match, case-insensitive). |
| has_leads | boolean When true, return only accounts with at least one associated lead. |
| include_disqualified | boolean Default: false When true, include disqualified leads in account aggregation. Defaults to false (qualified-only). |
{- "accounts": [
- {
- "account_id": "acc_123",
- "org_id": "org_1",
- "domain": "example.com",
- "name": "Example Inc",
- "created_at": "2024-01-01T00:00:00Z",
- "account_level": "High",
- "top_score": 612,
- "leads_count": 4,
- "owner_name": "Alex Rivera",
- "surging": true
}
], - "total": 1,
- "page": 1,
- "limit": 25
}Unlinks leads in the active OU from the given accounts and deletes account records that are no longer referenced by any lead.
| ids | Array of strings |
{- "ids": [
- "string"
]
}{- "account_id": "string",
- "org_id": "string",
- "domain": "string",
- "name": "string",
- "metadata": { },
- "top_score": 0,
- "leads": [
- {
- "lead_id": "string",
- "score": 0,
- "owner_name": "string",
- "last_event_at": "2019-08-24T14:15:22Z"
}
], - "recent_events": [
- {
- "id": "string",
- "lead_id": "string",
- "event_type": "string",
- "source": "string",
- "timestamp": "2019-08-24T14:15:22Z"
}
]
}Merges metadata into an account and optionally updates top-level name and domain fields. This is a partial update -- existing metadata keys not included in the request are preserved. OU-scoped to the active Organizational Unit.
| id required | string Account ID |
| name | string Update the account's company name. |
| domain | string Update the account's primary email domain. |
object Key-value pairs to merge into the account's metadata. Setting a key to null removes it. |
{- "name": "Acme Corporation",
- "domain": "acme.com",
- "metadata": {
- "industry": "Technology",
- "employees": 2500,
}
}Merges the source account (identified by {id}) into a target account. All leads and deals belonging to the source account are reassigned to the target account. The source account is then archived. This action is permanent and cannot be undone. Both accounts must belong to the same Organizational Unit. The merge is recorded in the audit log.
| id required | string The source account ID to be archived |
| target_id required | string The ID of the target account that will receive all leads and deals |
{- "target_id": "acct_def456"
}{- "leads_reassigned": 8,
- "deals_reassigned": 3
}Returns the aggregated Top-3 scoring factors across all qualified contacts associated with the account (the buying committee). Per-factor aggregation uses MAX contribution so the most-engaged contact's signal carries through rather than being diluted by less-engaged committee members.
DQ handling: disqualified contacts are excluded. When more than 50% of contacts
are disqualified, mostly_disqualified is set to true in the response.
When the account has no contacts (or all are disqualified), summary is
"No qualified contacts in this account." and factors is empty.
| accountID required | string The account ID |
{- "account_id": "string",
- "summary": "string",
- "factors": [
- {
- "dimension": "engagement",
- "rule_name": "string",
- "contribution": 0,
- "matched_value": "string",
- "event_count": 0,
- "days_since_fresh": 0,
- "phrase": "string"
}
], - "contributing_lead_count": 0,
- "total_contact_count": 0,
- "mostly_disqualified": true
}Evaluates an account scoring rule against a specific account without modifying production scores.
| lead_id required | string The lead whose account to test against |
required | object The account rule configuration to evaluate |
{- "lead_id": "string",
- "rule": {
- "account_property": "string",
- "condition": "equals",
- "comparison_value": "string",
- "weight": 0
}
}{- "matches": true,
- "reason": "string",
- "current_score": 0,
- "projected_score": 0,
- "matching_value": "string"
}[- {
- "id": "string",
- "org_id": "string",
- "name": "string",
- "enabled": true,
- "is_primary": true,
- "score_floor_pct": 0.5,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| name required | string |
| enabled | boolean |
| is_primary | boolean Default: false |
{- "name": "string",
- "enabled": true,
- "is_primary": false
}{- "id": "string",
- "org_id": "string",
- "name": "string",
- "enabled": true,
- "is_primary": true,
- "score_floor_pct": 0.5,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string |
| name required | string |
| enabled | boolean |
| is_primary | boolean Default: false |
{- "name": "string",
- "enabled": true,
- "is_primary": false
}| id required | string |
[- {
- "id": "string",
- "ruleset_id": "string",
- "account_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "half_life_days": 1,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}, - "ui_order": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| id required | string |
| account_property required | string |
| condition required | string |
| comparison_value required | string |
| weight required | integer |
| ui_order | integer |
| rule_type | string Enum: "add_points" "hard_disqualify" Defaults to add_points when omitted. |
object or null Compound AND/OR condition group. Only valid when rule_type is hard_disqualify. |
{- "account_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "ui_order": 0,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}
}{- "id": "string",
- "ruleset_id": "string",
- "account_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "half_life_days": 1,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}, - "ui_order": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}| id required | string |
| ruleId required | string |
| account_property | string |
| condition | string |
| comparison_value | string |
| weight | integer |
| ui_order | integer |
| rule_type | string Enum: "add_points" "hard_disqualify" |
object or null Compound AND/OR condition group. Only valid when rule_type is hard_disqualify. |
{- "account_property": "string",
- "condition": "string",
- "comparison_value": "string",
- "weight": 0,
- "ui_order": 0,
- "rule_type": "add_points",
- "conditions": {
- "op": "AND",
- "children": [
- {
- "property": "string",
- "condition": "string",
- "value": "string"
}
]
}
}Returns the audit log of all account mapping changes — creates, updates, and deletes — for the active OU.
[- {
- "id": "string",
- "mapping_type": "string",
- "action": "created",
- "actor": "string",
- "old_value": { },
- "new_value": { },
- "created_at": "2019-08-24T14:15:22Z"
}
]| source_field required | string |
| account_property required | string |
| update_behavior | string Default: "always_latest" Enum: "always_latest" "set_once" "append" Controls how this field is updated when new events arrive. For append, last 10 values are stored in " |
{- "source_field": "string",
- "account_property": "string",
- "update_behavior": "always_latest"
}{- "id": "string",
- "source_field": "string",
- "account_property": "string",
- "update_behavior": "always_latest",
- "created_at": "2019-08-24T14:15:22Z"
}| id required | string |
| source_field required | string |
| account_property required | string |
| update_behavior | string Default: "always_latest" Enum: "always_latest" "set_once" "append" Controls how this field is updated when new events arrive. For append, last 10 values are stored in " |
{- "source_field": "string",
- "account_property": "string",
- "update_behavior": "always_latest"
}Returns the buying committee members for an account, including their roles, engagement scores, and activity metrics.
| accountId required | string <uuid> Account identifier |
[- {
- "id": "string",
- "lead_id": "string",
- "account_id": "string",
- "role": "decision_maker",
- "engagement_score": 0,
- "activity_count": 0,
- "first_engagement_at": "2019-08-24T14:15:22Z",
- "last_engagement_at": "2019-08-24T14:15:22Z",
- "is_manual": true,
- "notes": "string",
- "best_alias": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "string",
- "title": "string",
- "company_name": "string",
- "engagement_level": "string",
- "profile_level": "string",
- "owner_name": "string"
}
]Manually add a lead to an account's buying committee with a specific role. Manually added members are preserved during automatic role refresh.
| accountId required | string <uuid> |
| lead_id required | string ID of the lead to add |
| role required | string Enum: "decision_maker" "influencer" "champion" "kol" "other" Committee role |
| notes | string Optional notes about this member |
{- "lead_id": "string",
- "role": "decision_maker",
- "notes": "string"
}{- "id": "string",
- "lead_id": "string",
- "account_id": "string",
- "role": "decision_maker",
- "engagement_score": 0,
- "activity_count": 0,
- "first_engagement_at": "2019-08-24T14:15:22Z",
- "last_engagement_at": "2019-08-24T14:15:22Z",
- "is_manual": true,
- "notes": "string",
- "best_alias": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "string",
- "title": "string",
- "company_name": "string",
- "engagement_level": "string",
- "profile_level": "string",
- "owner_name": "string"
}Re-runs role inference for auto-detected members based on current engagement data. Manually assigned roles are preserved.
| accountId required | string <uuid> |
[- {
- "id": "string",
- "lead_id": "string",
- "account_id": "string",
- "role": "decision_maker",
- "engagement_score": 0,
- "activity_count": 0,
- "first_engagement_at": "2019-08-24T14:15:22Z",
- "last_engagement_at": "2019-08-24T14:15:22Z",
- "is_manual": true,
- "notes": "string",
- "best_alias": "string",
- "first_name": "string",
- "last_name": "string",
- "email": "string",
- "title": "string",
- "company_name": "string",
- "engagement_level": "string",
- "profile_level": "string",
- "owner_name": "string"
}
]| accountId required | string <uuid> |
| lead_id required | string |
| role required | string Enum: "decision_maker" "influencer" "champion" "kol" "other" |
| notes | string |
{- "lead_id": "string",
- "role": "decision_maker",
- "notes": "string"
}Evaluates a deal scoring rule against a specific deal without modifying production scores.
| deal_id required | string The deal to test the rule against |
required | object The deal rule configuration to evaluate |
{- "deal_id": "string",
- "rule": {
- "deal_property": "string",
- "condition": "equals",
- "comparison_value": "string",
- "weight": 0
}
}{- "matches": true,
- "reason": "string",
- "current_score": 0,
- "projected_score": 0,
- "matching_value": "string"
}Returns every active hard-disqualification rule in the active OU across
both profile and account dimensions, together with the current count of
leads flagged by each rule (lead_scores.disqualified = TRUE).
Rules with zero matches are included so the UI can display all configured rules regardless of current activity.
Results are ordered by match_count DESC, rule_name ASC.
[- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "dimension": "profile",
- "rule_name": "string",
- "match_count": 42
}
]Returns paper §3 (B2B SaaS practitioner table) half-life defaults for
rules in the active OU that currently have half_life_days IS NULL.
Only engagement rules are eligible for suggestions; profile and account rules are firmographic-only and excluded per ADR-0048. Deal rules are fetched but always return ineligible (no event-type decay table applies).
The eligible_count field is the count to display on the "Apply research
defaults" button label in the UI.
| dimension | string Default: "all" Enum: "engagement" "all" Limit results to the engagement dimension. |
{- "eligible_count": 0,
- "ineligible_count": 0,
- "suggestions": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "event_type": "page_view",
- "current_half_life_days": 0,
- "suggested_half_life_days": 14,
- "source": "paper §3 (B2B SaaS practitioner table)"
}
]
}Applies paper §3 half-life values to each rule in rule_ids. Each
rule's outcome is independent — a per-rule failure does not roll back
other rules that have already been updated.
Skip reasons:
already_configured — rule already has a non-null half_life_days.no_research_default — event type not in the practitioner table, or
rule has no event_type (session-based).dimension_not_event_sourced — rule belongs to a profile, account,
or deal ruleset. These dimensions are current-state evaluation and do
not support half-life decay. Per ADR-0048 scoping correction.not_found — rule does not exist or belongs to a different OU.lookup_error — transient DB error during lookup.update_error — transient DB error during write.Audit trail: every applied rule writes a granular audit log entry
with actor = authenticated_user per ADR-0047 (GDPR Art. 22).
The request itself also generates a summary entry via the audit middleware.
| rule_ids required | Array of strings <uuid> non-empty [ items <uuid > ] Rule IDs to apply research defaults to. Must be non-empty. |
{- "rule_ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}{- "applied_count": 0,
- "skipped_count": 0,
- "results": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "dimension": "engagement",
- "applied_half_life_days": 0,
- "status": "applied",
- "reason": "already_configured"
}
]
}Returns the cached or freshly-computed calibration lift estimate for a single engagement scoring rule.
The ?force=1 query parameter forces a full recompute via ComputeAll
and persists the result before returning.
State variants:
no_conversion_definition — OU has no conversion definition configured.insufficient_cohort — fewer than 50 leads scored in the lookback window.never_computed — no cached result and force=1 was not passed, or the
rule had no activity in the lookback window.ready — calibration result present (possibly stale).| rulesetId required | string <uuid> |
| ruleId required | string <uuid> |
| force | string Value: "1" Pass |
{- "state": "no_conversion_definition",
- "required_action": "set_definition_in_ou_settings",
- "leads_scored": 0,
- "leads_required": 0,
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "current_weight": 0,
- "suggested_weight": 0,
- "sample_size": 0,
- "conversions_count": 0,
- "baseline_cr": 0.1,
- "rule_cr": 0.1,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
| ruleId required | string <uuid> |
| force | string Value: "1" |
{- "state": "no_conversion_definition",
- "required_action": "set_definition_in_ou_settings",
- "leads_scored": 0,
- "leads_required": 0,
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "current_weight": 0,
- "suggested_weight": 0,
- "sample_size": 0,
- "conversions_count": 0,
- "baseline_cr": 0.1,
- "rule_cr": 0.1,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
| ruleId required | string <uuid> |
| force | string Value: "1" |
{- "state": "no_conversion_definition",
- "required_action": "set_definition_in_ou_settings",
- "leads_scored": 0,
- "leads_required": 0,
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "current_weight": 0,
- "suggested_weight": 0,
- "sample_size": 0,
- "conversions_count": 0,
- "baseline_cr": 0.1,
- "rule_cr": 0.1,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
| ruleId required | string <uuid> |
| force | string Value: "1" |
{- "state": "no_conversion_definition",
- "required_action": "set_definition_in_ou_settings",
- "leads_scored": 0,
- "leads_required": 0,
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "current_weight": 0,
- "suggested_weight": 0,
- "sample_size": 0,
- "conversions_count": 0,
- "baseline_cr": 0.1,
- "rule_cr": 0.1,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}Returns all cached calibration runs for the given engagement scoring ruleset, joined with current rule metadata (name, weight).
The response includes a conversion_definition_summary block when the
OU has a conversion definition configured, and an empty runs array
when no calibration has been computed yet.
| rulesetId required | string <uuid> |
{- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "conversion_definition_summary": {
- "conversion_type": "closed_won",
- "lookback_days": 0,
- "deal_stages": [
- "string"
]
}, - "runs": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "rule_name": "string",
- "current_weight": 0,
- "suggested_weight": 0,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "sample_size": 0,
- "conversions_count": 0,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}
]
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
{- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "conversion_definition_summary": {
- "conversion_type": "closed_won",
- "lookback_days": 0,
- "deal_stages": [
- "string"
]
}, - "runs": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "rule_name": "string",
- "current_weight": 0,
- "suggested_weight": 0,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "sample_size": 0,
- "conversions_count": 0,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}
]
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
{- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "conversion_definition_summary": {
- "conversion_type": "closed_won",
- "lookback_days": 0,
- "deal_stages": [
- "string"
]
}, - "runs": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "rule_name": "string",
- "current_weight": 0,
- "suggested_weight": 0,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "sample_size": 0,
- "conversions_count": 0,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}
]
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| rulesetId required | string <uuid> |
{- "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
- "dimension": "engagement",
- "conversion_definition_summary": {
- "conversion_type": "closed_won",
- "lookback_days": 0,
- "deal_stages": [
- "string"
]
}, - "runs": [
- {
- "rule_id": "728c1541-d6d1-4290-9a53-cdf01dd32d60",
- "rule_name": "string",
- "current_weight": 0,
- "suggested_weight": 0,
- "raw_lift": 0.1,
- "shrunk_lift": 0.1,
- "sample_size": 0,
- "conversions_count": 0,
- "confidence": "insufficient",
- "co_occurrence_warnings": [
- {
- "other_rule_id": "0f18107a-e362-4e15-b00b-6c47ab5bc649",
- "overlap_pct": 0.1
}
], - "computed_at": "2019-08-24T14:15:22Z",
- "stale": true
}
]
}Applies a cached calibration run's suggested weight to the engagement scoring rule, writing a fully-attributed audit entry in the same transaction.
Rejection paths:
404 rule_not_found — rule does not exist or belongs to a different OU.400 no_conversion_definition — OU has no conversion definition.400 never_computed — no calibration run found; call GET ?force=1 first.409 stale_calibration — computed_at is older than 14 days.400 insufficient_sample — suggested_weight is nil (low confidence).| ruleId required | string <uuid> |
{- "prior_weight": 0,
- "new_weight": 0,
- "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| ruleId required | string <uuid> |
{- "prior_weight": 0,
- "new_weight": 0,
- "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| ruleId required | string <uuid> |
{- "prior_weight": 0,
- "new_weight": 0,
- "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}Identical semantics to the engagement variant. See that endpoint for full documentation.
| ruleId required | string <uuid> |
{- "prior_weight": 0,
- "new_weight": 0,
- "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}Returns snapshots of the engagement level configuration, saved each time a level is created, updated, or deleted.
| ruleset_id required | string The ruleset ID to retrieve history for |
[- {
- "id": "string",
- "ruleset_id": "string",
- "score_type": "string",
- "snapshot": [
- { }
], - "actor": "string",
- "created_at": "2019-08-24T14:15:22Z"
}
]Replaces the current engagement level configuration with a previously saved snapshot.
| history_id required | string ID of the history entry to revert to |
{- "history_id": "string"
}Returns snapshots of the profile level configuration, saved each time a level is created, updated, or deleted.
| ruleset_id required | string |
[- { }
]Returns snapshots of the account level configuration, saved each time a level is created, updated, or deleted.
| ruleset_id required | string |
[- { }
]| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}{- "stage_id": "st_hot",
- "name": "Hot",
- "min_score": 80,
- "max_score": 1000
}| id required | string |
| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}Lists configured profile levels within the active OU.
[- {
- "level_id": "string",
- "name": "string",
- "min_score": 0,
- "max_score": 0,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}
]| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}{- "level_id": "string",
- "name": "string",
- "min_score": 0,
- "max_score": 0,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}Lists configured account levels within the active OU.
[- {
- "level_id": "string",
- "name": "string",
- "min_score": 0,
- "max_score": 0,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}
]| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}{- "level_id": "string",
- "name": "string",
- "min_score": 0,
- "max_score": 0,
- "org_id": "string",
- "created_by": "string",
- "updated_by": "string"
}| id required | string |
| name required | string |
| min_score required | integer |
| max_score required | integer |
{- "name": "string",
- "min_score": 0,
- "max_score": 0
}Updates scoring settings (organization-wide toggles plus per-OU session idle timeout for the active OU).
| allow_negative_scores | boolean |
| abm_enabled | boolean |
| session_timeout_minutes | integer |
{- "allow_negative_scores": true,
- "abm_enabled": true,
- "session_timeout_minutes": 0
}