kenbun API (1.0.0)

Download OpenAPI specification:

kenbun API for event ingestion, scoring, segments, triggers, and organization unit (OU) workflows. Notes on scoping and security:

  • Most endpoints are organization-scoped and also OU-scoped. The server derives org and OU from the authenticated context.
  • OU is selected via POST /org-units/active which sets an HttpOnly cookie named activeOu. Many endpoints require an active OU.
  • Clients must not send unit_id in requests; the server uses the active OU from context.
  • For SPA/browser clients, JWT Bearer tokens are used. API clients can also use HTTP Basic with a client_id and client_secret.

Root

Prometheus metrics

Exposes Prometheus metrics in text format. No authentication required.

Responses

Response samples

Content type
text/plain; version=0.0.4
# 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

Root

Returns the SPA index page or a simple health/info payload.

Responses

Response samples

Content type
application/json
{
  • "status": "ok"
}

Home

Returns the SPA home page when Accept contains text/html; otherwise a small JSON payload for health checks.

Responses

Response samples

Content type
application/json
{
  • "status": "ok",
  • "page": "home"
}

Auth

Cleanup legacy auth cookies

Removes any residual cookies from previous auth flows.

Responses

Current user

Returns the authenticated user's basic profile. Requires a valid JWT.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "org_member_id": "om_abc123",
  • "first_name": "Jane",
  • "last_name": "Doe",
  • "email": "jane@example.com",
  • "role": "admin",
  • "verified": true
}

Events

Ingest engagement event

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, OR
  • one or more entries in the aliases 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.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
lead_id
string

Existing lead identifier; optional when aliases are provided

alias_kind
string
Enum: "email" "phone" "external_id" "cookie" "social"

Deprecated. Use aliases array.

alias
string

Deprecated. Use aliases array.

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'.

Responses

Request samples

Content type
application/json
Example
{
  • "lead_id": "ld_123",
  • "event_type": "Page View",
  • "timestamp": "2025-08-15T12:00:00Z",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "message": "event ingested",
  • "metadata": {
    }
}

Log a LinkedIn outbound touch

Manual fallback for logging a LinkedIn connection request or message. Constructs the same behavioral event as the extension auto-capture path (source='linkedin_extension_manual', alias_kind='social') and funnels it through scoring + the HubSpot fan-out.

Requires authentication and an active OU. Org and OU are derived from the authenticated context; clients must not send unit_id.

linkedin_url is canonicalized server-side (lowercase, no scheme/www/trailing slash) so duplicate URLs with different casing resolve to the same lead.

log_to_hubspot defaults to true. Set false to score in kenbun only.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
activity_type
required
string
Enum: "connection_request_sent" "message_sent"

Type of LinkedIn outbound touch.

linkedin_url
required
string

Raw or canonical LinkedIn profile URL (e.g. https://linkedin.com/in/jane-doe).

recipient_name
string

Display name of the recipient (for HubSpot note body).

body
string

Message body (included in the HubSpot note only when provided; consent-gated by the caller).

idempotency_key
string

Stable key to prevent double-writes across retries. Generated server-side when absent.

log_to_hubspot
boolean
Default: true

Fan-out the touch to HubSpot as a Note engagement. Set false to score in kenbun only.

Responses

Request samples

Content type
application/json
Example
{
  • "activity_type": "connection_request_sent",
  • "recipient_name": "Jane Doe",
  • "idempotency_key": "linkedin.com/in/jane-doe|2026-06-03T14:00:00Z"
}

Response samples

Content type
application/json
{
  • "message": "activity logged",
  • "lead_id": "550e8400-e29b-41d4-a716-446655440000",
  • "event_type": "LinkedIn Connection Request Sent"
}

Import events from CSV

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).

Authorizations:
bearerAuthbasicAuth
Request Body schema: multipart/form-data
required
file
string <binary>

CSV file with header row

Responses

Response samples

Content type
application/json
{
  • "message": "string"
}

List visible event types (OU-scoped)

Returns event type names visible in the active OU (excludes hidden types).

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • "string"
]

List distinct metadata keys for an event type (OU)

path Parameters
eventType
required
string

Responses

Response samples

Content type
application/json
{
  • "event_type": "string",
  • "properties": [
    ]
}

List engagement events (OU-scoped)

Returns events limited to the active Organization Unit (OU).

Authorizations:
bearerAuthbasicAuth
query Parameters
page
integer >= 1
Default: 1
limit
integer [ 1 .. 500 ]
Default: 50
bot
string
Enum: "hide" "only"

Likely-bot view filter. hide excludes events classified as likely bots (from the visitor's browser); only returns just those. Omit for all events. The convenience alias hide_bots=true is equivalent to bot=hide.

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

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Batch delete events (OU-scoped)

Deletes events by IDs scoped to the active OU.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
ids
Array of strings

Responses

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

List events for a lead (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get event score explanation

Returns per-ruleset score deltas and before/after totals for a single event.

Authorizations:
bearerAuthbasicAuth
path Parameters
eventID
required
string

Responses

Response samples

Content type
application/json
{
  • "event_id": "string",
  • "lead_id": "string",
  • "event_type": "string",
  • "occurred_at": "2019-08-24T14:15:22Z",
  • "rulesets": [
    ]
}

Export events (OU-scoped)

Downloads events as CSV for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
text/csv
id,lead_id,event_type,timestamp
ev_001,ld_123,Page View,2025-08-15T12:00:00Z

List available channels (OU-scoped)

Returns distinct normalized channels observed in the active OU (e.g., web, email, slack, webinar, crm).

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • "web",
  • "email",
  • "slack"
]

Unified activity stream (events + orders + timeline)

Returns a composite view of lead activity: filtered engagement events, orders, and a unified timeline.

Unified Activity Stream (ADR-0010):

  • Events: behavioral engagement from engagement_events table
  • Orders: transactional records from orders table (represented as synthetic activity projections)
  • Timeline: merged chronological view sorted by timestamp

OU Scoping: Only returns data for the caller's active Organizational Unit.

Synthetic Order Projections:

  • Orders appear in the orders array and timeline with type: "order"
  • These are ephemeral, read-only projections created on-demand
  • NOT persisted to engagement_events table
  • NOT scored as engagement events

Filtering behavior:

  • range, start, end: Apply to both events and orders
  • channel, minScore, maxLatency, hasDelta: Apply to events only
Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Lead UUID

query Parameters
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)

Responses

Response samples

Content type
application/json
{
  • "events": [
    ],
  • "orders": [
    ],
  • "timeline": [
    ]
}

Analytics

Pre-aggregated overview metrics (OU-scoped)

Server-aggregated metrics for the Overview dashboard: event/lead counts with prior-period deltas, the engagement x profile distribution matrix, the 7-day activity heatmap, deals summary, and the single hottest lead (hot_lead) at or above the hot threshold for the "Act now" banner. hot_lead is null when no lead currently clears the threshold.

Authorizations:
bearerAuthbasicAuth
query Parameters
days
integer
Default: 7

Length of the current period in days (prior period is the same length immediately before it).

Responses

Response samples

Content type
application/json
{
  • "events_count": 220,
  • "active_leads_count": 84,
  • "hot_leads_count": 1,
  • "new_leads_count": 82,
  • "hot_threshold": 120,
  • "deals_enabled": false,
  • "hot_lead": {
    }
}

Analytics across events (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "totals": {
    },
  • "by_type": {
    }
}

Event statistics (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "last_24h": {
    },
  • "top_events": [
    ]
}

Top leads (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Recent score gains (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Deal attribution insights (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "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": [
    ]
}

Aggregated UTM campaign performance (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
group_by
string
Default: "campaign"
Enum: "campaign" "source" "medium"

Which UTM key to aggregate on. Defaults to campaign.

start_date
string

Lower bound for event occurred_at. Accepts YYYY-MM-DD or RFC3339.

end_date
string

Upper bound for event occurred_at. Accepts YYYY-MM-DD or RFC3339.

Responses

Response samples

Content type
application/json
{
  • "group_by": "campaign",
  • "campaigns": [
    ]
}

Leads attributed to a single UTM campaign value (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
campaign_name
required
string

Exact UTM value to look up. URL-encode if it contains spaces or special characters.

query Parameters
group_by
string
Default: "campaign"
Enum: "campaign" "source" "medium"

Which UTM key to match campaign_name against. Should match the grouping used to discover the value.

start_date
string

Lower bound for event occurred_at. Accepts YYYY-MM-DD or RFC3339.

end_date
string

Upper bound for event occurred_at. Accepts YYYY-MM-DD or RFC3339.

Responses

Response samples

Content type
application/json
{
  • "campaign_name": "string",
  • "leads": [
    ]
}

Recent score gains (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Leads

Batch lead scores for visible leads (OU-scoped, engagement primary ruleset by default)

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.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
lead_ids
required
Array of strings [ 1 .. 500 ] items
ruleset
string

primary (default) or a specific ruleset_id/name

Responses

Request samples

Content type
application/json
{
  • "lead_ids": [
    ],
  • "ruleset": "string"
}

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Get lead score (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead_id": "ld_123",
  • "score": 87
}

List lead scores (OU-scoped)

Returns lead scores for the active Organizational Unit (OU). When page or limit is provided, the response includes pagination metadata (total, page, limit). Notes:

  • All data is scoped to the active OU selected via POST /org-units/active.
  • Accounts have a unit_id attribute; do not supply unit_id from clients.
Authorizations:
bearerAuthbasicAuth
query Parameters
page
integer >= 1
Default: 1
limit
integer [ 1 .. 500 ]
Default: 50
bot
string
Enum: "hide" "only"

Likely-bot view filter. hide excludes leads whose engagement is entirely from likely bots (a lead with any human activity, or none, is kept); only returns just those. Omit for all leads. The alias hide_bots=true is equivalent to bot=hide.

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).

disposition
string
Example: disposition=accepted_sql,nurture

Filter by sales disposition. Comma-separated list of one or more of the six outcome values (accepted_sql, rejected_not_icp, rejected_no_response, nurture, closed_won, closed_lost) plus the sentinel none, which matches leads with no disposition set. For example, disposition=accepted_sql,nurture returns leads marked Qualified or Nurture; disposition=none returns un-dispositioned leads. An unrecognized value returns 400. The same parameter is honored by the CSV export at GET /leads/export.csv.

Responses

Response samples

Content type
application/json
{
  • "leads": [
    ],
  • "total": 2,
  • "page": 1,
  • "limit": 25
}

Create a new lead (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
id
required
string
object
account_id
string or null

Responses

Request samples

Content type
application/json
{
  • "id": "string",
  • "metadata": { },
  • "account_id": "string"
}

Response samples

Content type
application/json
{
  • "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": { }
}

Export leads as CSV (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
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"

Responses

Search leads by ID or alias (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
q
required
string >= 2 characters

Search query (minimum 2 characters)

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get a lead including metadata and related account (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead": {
    },
  • "account": { }
}

Patch lead metadata (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string
Request Body schema: application/json
required
property name*
additional property
any

Request samples

Content type
application/json
{ }

List lead aliases (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Get lead profile metadata (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Get lead account metadata (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Get lead score including disqualification state (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead_id": "string",
  • "score": 0,
  • "disqualified": true,
  • "disqualified_by_rule_id": "string",
  • "disqualified_at": "2019-08-24T14:15:22Z",
  • "disqualified_reason": "string"
}

Get ranked scoring factors and plain-language summary for a single lead (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead_id": "string",
  • "summary": "string",
  • "factors": [
    ],
  • "disqualified": true,
  • "disqualification": {
    }
}

Summarize sales disposition activity for the active OU

Returns aggregate sales-disposition feedback for the active Organizational Unit: total dispositions, distinct setters, the most active setter's share, per-outcome counts with average stamped score under the current scoring rules version, and up to 10 of the most recent rep notes.

Per-outcome average scores are restricted to dispositions stamped with the OU's current primary engagement ruleset version (current_ruleset_version_id). Merged-away leads and sample (demo) leads are excluded from every figure.

Authorizations:
bearerAuthbasicAuth
query Parameters
since_days
integer [ 1 .. 365 ]
Default: 90

Look-back window in days. Defaults to 90; clamped to 1–365.

Responses

Response samples

Content type
application/json
{
  • "since_days": 90,
  • "total": 18,
  • "distinct_actors": 5,
  • "top_actor_share": 0.44,
  • "current_ruleset_version_id": "8b2e0c1a-3d4f-4a5b-9c6d-7e8f9a0b1c2d",
  • "by_disposition": [
    ],
  • "recent_comments": [
    ]
}

Score-vs-outcome quality report for the active OU

Compares the score kenbun gave each lead against the outcome sales actually logged, so you can see where scoring agreed with sales and where it did not. Powers the Score vs. Outcome view on the calibration review page (Configure > Scoring).

The report has four parts:

  • False positives — leads that scored high yet were rejected by sales.
  • False negatives — leads that scored low yet were qualified or won.
  • Distribution — the spread of stamped scores per outcome (lowest, 25th percentile, median, 75th percentile, highest).
  • Time to disposition — how long, on average and at the median, leads waited between owner assignment and an outcome being logged.

Every figure uses the score stamped at the moment each outcome was logged. Merged-away leads and sample (demo) leads are excluded.

Authorizations:
bearerAuthbasicAuth
query Parameters
since_days
integer [ 1 .. 365 ]
Default: 90

Look-back window in days. Defaults to 90; clamped to 1–365.

high_score
integer >= 0

The score at or above which a rejected lead counts as a false positive. When omitted, kenbun derives it from your highest engagement level threshold, falling back to 75.

low_score
integer >= 0
Default: 40

The score below which a qualified or won lead counts as a false negative. Defaults to 40.

limit
integer [ 1 .. 100 ]
Default: 25

Maximum leads returned in each of the false-positive and false-negative lists. Defaults to 25; clamped to 100.

Responses

Response samples

Content type
application/json
{
  • "since_days": 90,
  • "high_score": 75,
  • "low_score": 40,
  • "current_ruleset_version_id": "8b2e0c1a-3d4f-4a5b-9c6d-7e8f9a0b1c2d",
  • "false_positives": [
    ],
  • "false_negatives": [
    ],
  • "distribution": [
    ],
  • "time_to_disposition": [
    ]
}

Export the false-positive and false-negative lists as CSV

Streams the false-positive and false-negative leads from the disposition quality report as a single CSV. A section column labels each row as false_positive or false_negative. Accepts the same query parameters as GET /leads/disposition-quality.

Authorizations:
bearerAuthbasicAuth
query Parameters
since_days
integer [ 1 .. 365 ]
Default: 90
high_score
integer >= 0
low_score
integer >= 0
Default: 40
limit
integer [ 1 .. 100 ]
Default: 25

Responses

Set or update the sales disposition on a lead (OU-scoped)

Records a one-tap sales outcome on a lead. The lead's engagement score and scoring-rules version are stamped automatically at the moment the disposition is set, forming a labeled outcome record used by the calibration engine.

Setting a disposition never changes scoring weights — weight changes are a separate, human-approved action under Configure > Scoring.

Comment behavior: omit comment to preserve it on a same-outcome re-save (it is cleared when the outcome changes); send an empty/whitespace string to clear it; send text to set it (trimmed, max 2000 characters).

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string <uuid>
Request Body schema: application/json
required
disposition
required
string
Enum: "accepted_sql" "rejected_not_icp" "rejected_no_response" "nurture" "closed_won" "closed_lost"

The sales outcome. accepted_sql is labeled "Qualified (SQL)" in the UI.

comment
string or null <= 2000 characters

Optional rep note shown to marketing operations; never used in scoring math.

Responses

Request samples

Content type
application/json
{
  • "disposition": "accepted_sql",
  • "comment": "Booked a demo"
}

Response samples

Content type
application/json
{
  • "status": "ok",
  • "disposition": {
    },
  • "previous": {
    },
  • "restamped": true
}

Clear the sales disposition on a lead (OU-scoped)

Removes the disposition from a lead, returning it to the "no disposition" state. The response echoes the outcome that was cleared so callers can confirm what was removed. Clearing a lead that had no disposition is a no-op success with previous: null.

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "status": "ok",
  • "previous": {
    }
}

Batch plain-language scoring summaries for multiple leads (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "summaries": {
    },
  • "missing": [
    ]
}

Get a lead including metadata and related account (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead": {
    },
  • "account": { }
}

Update a lead (replace metadata, optionally account)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string
Request Body schema: application/json
required
object
account_id
string or null

Responses

Request samples

Content type
application/json
{
  • "metadata": { },
  • "account_id": "string"
}

Delete a lead (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Create a new lead (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
id
required
string
object
account_id
string or null

Responses

Request samples

Content type
application/json
{
  • "id": "string",
  • "metadata": { },
  • "account_id": "string"
}

Response samples

Content type
application/json
{
  • "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": { }
}

Lead deletion status (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "lead_id": "ld_123",
  • "status": "completed"
}

List lead aliases (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Patch lead metadata (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
leadID
required
string
Request Body schema: application/json
required
property name*
additional property
any

Responses

Request samples

Content type
application/json
{
  • "industry": "SaaS",
  • "plan": "Pro"
}

Response samples

Content type
application/json
{
  • "id": "ld_123",
  • "org_id": "org_1",
  • "unit_id": "unit_default",
  • "metadata": {
    }
}

Look up a lead by alias (e.g., email)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
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).

Responses

Response samples

Content type
application/json
{
  • "lead_id": "ld_abc123",
  • "email": "alex@example.com",
  • "metadata": {
    }
}

Update lead metadata by alias

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.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
Example
{
  • "alias_kind": "email",
  • "alias_value": "alex@example.com",
  • "attributes": {
    }
}

Response samples

Content type
application/json
Example
{
  • "lead_id": "ld_abc123",
  • "updated": 2,
  • "attributes": {
    },
  • "account_linked": false
}

Merge leads (OU-scoped)

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'.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
targetLeadId
required
string
sourceLeadIds
required
Array of strings
object

Responses

Request samples

Content type
application/json
{
  • "targetLeadId": "string",
  • "sourceLeadIds": [
    ],
  • "truncate": {
    }
}

Response samples

Content type
application/json
{
  • "target": {
    },
  • "mergedSources": [
    ],
  • "movedEvents": 0,
  • "truncatedEvents": 0,
  • "rescore": {
    }
}

Get score explanation

Returns top drivers, a rule weights snapshot, and surge boost contributions for the specified lead. OU scoped; time window defaults to last 24 hours.

path Parameters
leadID
required
string
query Parameters
hours
integer >= 1
Default: 24

Responses

Response samples

Content type
application/json
{
  • "top_drivers": [
    ],
  • "snapshot": [
    ],
  • "surge_boost": [
    ],
  • "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
}

Create a shareable score explanation link

Creates a read-only, time-limited link to a lead's score explanation. Recipients can view the full score breakdown without a kenbun account. Links expire after 7 days.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Lead identifier

Responses

Response samples

Content type
application/json
{
  • "token": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "share_url": "string"
}

Reset lead engagement scores

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.

path Parameters
leadID
required
string

Responses

Response samples

Content type
application/json
{
  • "status": "ok",
  • "lead_id": "string",
  • "previous_scores": {
    }
}

Assign or unassign lead owner

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.

Authorizations:
bearerAuth
path Parameters
leadID
required
string <uuid>

Lead identifier

Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "owner_id": "string",
  • "owner_name": "string"
}

Response samples

Content type
application/json
{
  • "status": "ok",
  • "message": "owner assigned"
}

Bulk assign lead owner

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "lead_ids": [
    ],
  • "owner_id": "string",
  • "owner_name": "string"
}

Response samples

Content type
application/json
{
  • "status": "ok",
  • "affected": 0
}

Rules

List scoring rules in a set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Reorder scoring rules in a ruleset (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Ruleset identifier

Request Body schema: application/json
required
rule_ids
required
Array of strings

Rule IDs in the desired priority order (highest priority first)

Responses

Request samples

Content type
application/json
{
  • "rule_ids": [
    ]
}

List scoring rules (OU-scoped)

Returns all scoring rules for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create scoring rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "event_type": "Email Open",
  • "weight": 5,
  • "active": true
}

Response samples

Content type
application/json
{
  • "rule_id": "rl_2",
  • "ruleset_id": "rs_default",
  • "event_type": "Email Open",
  • "weight": 5,
  • "active": true
}

Update scoring rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "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"
}

Delete scoring rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Test an engagement scoring rule against a lead (dry run)

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.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
lead_id
required
string

The lead to test the rule against

required
object

The rule configuration to evaluate

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "rule": {
    }
}

Response samples

Content type
application/json
{
  • "matches": true,
  • "reason": "string",
  • "current_score": 0,
  • "projected_score": 0,
  • "matching_events": 0
}

Trigger on-demand scoring for a ruleset (OU-scoped)

Immediately rescores all leads in the active OU against the specified ruleset. Works for any scoring dimension (engagement, profile, account, deal).

Authorizations:
bearerAuthbasicAuth
path Parameters
dimension
required
string
Enum: "engagement" "profile" "account" "deal"

The scoring dimension

id
required
string

The ruleset identifier

Responses

List surge triggers (OU-scoped)

Returns all surge triggers for the active organizational unit.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create surge trigger (OU-scoped)

Creates a new surge trigger for the active organizational unit.

Authorizations:
bearerAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "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": [
    ],
  • "slack_target_kind": "channel",
  • "slack_target_id": "string",
  • "teams_webhook_url": "string"
}

Response samples

Content type
application/json
{
  • "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": [
    ],
  • "emails": [
    ],
  • "active": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update surge trigger

Updates an existing surge trigger by ID.

Authorizations:
bearerAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "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": [
    ],
  • "slack_target_kind": "channel",
  • "slack_target_id": "string",
  • "teams_webhook_url": "string"
}

Preview (backtest) a surge trigger

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.

Authorizations:
bearerAuth
path Parameters
id
required
string

Surge trigger ID

Request Body schema: application/json
optional
days
integer [ 1 .. 90 ]
Default: 30

Number of days of event history to scan (1–90, default 30)

Responses

Request samples

Content type
application/json
{
  • "days": 30
}

Response samples

Content type
application/json
{
  • "would_fire_count": 5,
  • "sample_leads": [
    ]
}

Get health for a surge trigger (OU-scoped)

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).

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Surge trigger ID

Responses

Response samples

Content type
application/json
{
  • "delivered_24h": 0,
  • "failed_24h": 3,
  • "last_failure_at": "2026-05-12T01:12:13Z",
  • "last_error": "connection timeout after 30s",
  • "status": "red",
  • "recent_attempts": [
    ]
}

Simulate a surge trigger against a specific lead

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.

Authorizations:
bearerAuth
path Parameters
id
required
string

Surge trigger ID

Request Body schema: application/json
required
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)

Responses

Request samples

Content type
application/json
{
  • "lead_id": "ld_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  • "days": 30
}

Response samples

Content type
application/json
{
  • "would_fire": true,
  • "total_matches": 2,
  • "message": "Trigger would have fired 2 time(s) for this lead in the last 30 days",
  • "matched_windows": [
    ]
}

List surge events (OU-scoped)

Returns surge events for the active organizational unit. Surge events are recorded each time a surge trigger fires.

Authorizations:
bearerAuth
query Parameters
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).

Responses

Response samples

Content type
application/json
Example
[ ]

Delete surge trigger

Authorizations:
bearerAuth
path Parameters
id
required
string

Responses

RuleSets

List scoring rule sets (OU-scoped)

Lists all scoring rulesets available in the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create scoring rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
string
score_column
string
Default: "total_score"
is_primary
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "name": "Marketing",
  • "score_column": "total_score"
}

Response samples

Content type
application/json
{
  • "ruleset_id": "rs_marketing",
  • "name": "Marketing",
  • "score_column": "total_score"
}

Delete a scoring ruleset (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Profile

Test a profile scoring rule against a lead (dry run)

Evaluates a profile scoring rule against a specific lead without modifying production scores.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
lead_id
required
string

The lead to test the rule against

required
object

The profile rule configuration to evaluate

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "rule": {
    }
}

Response samples

Content type
application/json
{
  • "matches": true,
  • "reason": "string",
  • "current_score": 0,
  • "projected_score": 0,
  • "matching_value": "string"
}

List profile field mappings (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create profile field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
source_field
required
string
profile_property
required
string

Responses

Request samples

Content type
application/json
{
  • "source_field": "utm_source",
  • "profile_property": "acquisition_source"
}

Response samples

Content type
application/json
{
  • "id": "pm_2",
  • "source_field": "utm_source",
  • "profile_property": "acquisition_source"
}

Update profile field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
source_field
required
string
profile_property
required
string

Responses

Request samples

Content type
application/json
{
  • "source_field": "string",
  • "profile_property": "string"
}

Delete profile field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List profile rule sets (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create profile rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
enabled
boolean
is_primary
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "enabled": true,
  • "is_primary": false
}

Response samples

Content type
application/json
{
  • "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"
}

Update profile rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
enabled
boolean
is_primary
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "enabled": true,
  • "is_primary": false
}

Delete profile rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List profile rules in a set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create profile rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "profile_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "ui_order": 0,
  • "rule_type": "add_points",
  • "conditions": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "ruleset_id": "string",
  • "profile_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "half_life_days": 1,
  • "rule_type": "add_points",
  • "conditions": {
    },
  • "ui_order": 0,
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update profile rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
ruleId
required
string
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "profile_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "ui_order": 0,
  • "rule_type": "add_points",
  • "conditions": {
    }
}

Get profile mapping change history (OU-scoped)

Returns the audit log of all profile mapping changes — creates, updates, and deletes — for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List distinct lead metadata properties (OU-scoped)

Returns distinct keys observed in lead metadata for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • "industry",
  • "plan",
  • "company",
  • "role"
]

Segments

Compare overlap between two segments (OU-scoped)

Returns the number of leads that appear in both segments, plus counts for each segment individually.

Authorizations:
bearerAuthbasicAuth
query Parameters
a
required
string

ID of the first segment

b
required
string

ID of the second segment

Responses

Response samples

Content type
application/json
{
  • "a_count": 0,
  • "b_count": 0,
  • "overlap_count": 0,
  • "overlap_pct_a": 0,
  • "overlap_pct_b": 0
}

List segments (OU-scoped)

Lists segments defined for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create segment (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
description
string
active
boolean

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "active": true
}

Response samples

Content type
application/json
{
  • "segment_id": "sg_marketing",
  • "name": "Marketing Leads",
  • "description": "Leads from marketing sources",
  • "active": true
}

Update segment (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
description
string
active
boolean

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "active": true
}

Delete segment (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Count leads in a segment (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
query Parameters
include_disqualified
boolean
Default: false

When true, include disqualified leads in the count. Defaults to false (qualified-only).

Responses

Response samples

Content type
application/json
{
  • "count": 0
}

List leads in a segment (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
query Parameters
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).

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List segment rules (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create segment rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "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
}

Response samples

Content type
application/json
{
  • "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"
}

Update segment rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
ruleId
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "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
}

Delete segment rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
ruleId
required
string

Responses

Stages

Decays

List score decay rules (OU-scoped)

Retrieves decay rules that reduce scores after inactivity, scoped to the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create score decay rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
inactive_for
required
integer

Duration amount

unit
required
string
Enum: "days" "hours" "weeks"
decrease
required
integer

Score decrease amount

Responses

Request samples

Content type
application/json
{
  • "inactive_for": 0,
  • "unit": "days",
  • "decrease": 0
}

Response samples

Content type
application/json
{
  • "decay_id": "dc_inactive30d",
  • "inactive_for": 30,
  • "unit": "days",
  • "decrease": 25
}

Update score decay rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
inactive_for
integer
unit
string
Enum: "days" "hours" "weeks"
decrease
integer

Responses

Request samples

Content type
application/json
{
  • "inactive_for": 0,
  • "unit": "days",
  • "decrease": 0
}

Delete score decay rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Filters

List inorganic filters (OU-scoped)

Lists configured inorganic activity filters used to flag bot-like activity in the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create inorganic filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
event_type
required
string
count_threshold
required
integer
time_window_ms
required
integer
group_events
boolean

Responses

Request samples

Content type
application/json
{
  • "event_type": "string",
  • "count_threshold": 0,
  • "time_window_ms": 0,
  • "group_events": true
}

Response samples

Content type
application/json
{
  • "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"
}

Update inorganic filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
event_type
string
count_threshold
integer
time_window_ms
integer
group_events
boolean

Responses

Request samples

Content type
application/json
{
  • "event_type": "string",
  • "count_threshold": 0,
  • "time_window_ms": 0,
  • "group_events": true
}

Delete inorganic filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

MetadataFilters

Attribute based filters suppress engagement events whose metadata matches key/value conditions. Evaluated before velocity based filters.

List attribute based filters (OU-scoped)

Returns all metadata attribute filters for the active OU, sorted enabled-first then newest-first.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create attribute based filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "event_type": "string",
  • "conditions": [
    ],
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "unit_id": "string",
  • "name": "string",
  • "event_type": "string",
  • "conditions": [
    ],
  • "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"
}

Preview suppression count for given conditions (OU-scoped)

Runs the provided conditions against existing events and returns how many would be suppressed. Does not persist any changes.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
event_type
string

Scope preview to a specific event type. Omit for all types.

required
Array of objects (MetadataAttributeFilterCondition)

Responses

Request samples

Content type
application/json
{
  • "event_type": "string",
  • "conditions": [
    ]
}

Response samples

Content type
application/json
{
  • "count": 0
}

Get attribute based filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{
  • "id": "string",
  • "unit_id": "string",
  • "name": "string",
  • "event_type": "string",
  • "conditions": [
    ],
  • "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"
}

Update attribute based filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
event_type
string
Array of objects (MetadataAttributeFilterCondition)
enabled
boolean

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "event_type": "string",
  • "conditions": [
    ],
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "unit_id": "string",
  • "name": "string",
  • "event_type": "string",
  • "conditions": [
    ],
  • "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"
}

Delete attribute based filter (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Scoring

Scoring endpoints compute and explain lead, profile, and account scores. POST /scoring/score is a synchronous, multi-dimension scorer that returns the full result (score, level, drivers, disqualification) in the response body. All endpoints are organization- and OU-scoped; org and OU are derived from the authenticated context.

Score a signal synchronously across one or more dimensions

Synchronous, in-process multi-dimension scorer. Unlike POST /ingest (which returns 202 and scores asynchronously), this endpoint computes the score in the request path and returns the full result — score, level, drivers, and disqualification status — in a 200 body.

The lead is resolved-or-created by external_id (alias kind external_id). At least one scorable dimension is required: event (engagement), profile (firmographic fit), and/or account (company fit). Only the dimensions you POST are scored and returned. Deal scoring is out of scope.

Each dimension's score is the deterministic score of the POSTed object under its ruleset — NOT the lead's cumulative decaying lifetime total. Identical input yields identical output.

Enrichment (persistence). Beyond scoring, this endpoint can also write the data you POST onto the lead and its company:

  • When profile is supplied, its firmographic attributes are merged onto the lead's stored profile/metadata. This requires the token to also hold the write:leads scope; otherwise the request fails with 403 insufficient_scope.
  • When account is supplied, a company (account) is resolved-or-created and the lead is linked to it. Resolution order is: the account's external_id (CRM company id) if provided, else its domain, else its name. The POSTed firmographics are merged onto the account, and the linked account id is returned as account_id. This requires the token to also hold the write:accounts scope; otherwise the request fails with 403 insufficient_scope.

The response's enriched object reports which records were persisted (for example, {"lead": true, "account": true}). An event-only call scores without persisting profile or account data and needs only write:scoring; a full create-score-enrich call needs write:scoring, write:leads, and write:accounts.

Honest results: a genuine score of 0 returns 200; a disqualified lead returns 200 with disqualified: true; failures return 4xx/5xx so callers can always distinguish "scored zero" from "could not score".

Idempotent: pass idempotency_key (for example, an n8n execution id) to make retries safe. A replay returns the stored result with cached: true. If omitted, a key is derived from the request contents.

Authentication: a Personal Access Token (PAT) with the write:scoring scope (plus write:leads and/or write:accounts when posting profile or account, see above). The server derives org_id and unit_id from the token; clients must not send unit_id.

Authorizations:
bearerAuth
Request Body schema: application/json
required
external_id
required
string

External identifier used to resolve or create the lead (alias kind external_id).

idempotency_key
string

Optional. Make retries safe; a replay returns the stored result with cached:true. Derived from request contents if omitted.

triggers_enabled
boolean
Default: false

When true, downstream notifications/automations may fire for the engagement signal. Defaults to false.

source
string
Default: "score"

Optional traffic source label. Defaults to 'score'. The reserved values 'test' and 'sample_data' are rejected.

object (ScoreSyncRulesets)

Optional per-dimension ruleset names. Omit a dimension to use its primary ruleset. Never more than one ruleset per dimension.

object (ScoreSyncEvent)

An engagement signal to score against the engagement ruleset. kenbun events are channel-agnostic: the event itself carries only what kind of thing happened (event_type), when it happened (occurred_at), and a free-form metadata object. Anything descriptive — marketing channel, source URL, post text, or any custom attribute — goes inside metadata, which is what engagement attribute-filter rules match against.

object

Firmographic profile attributes (role, company_size, industry, icp_tier, ...). Scored against the profile ruleset. When supplied, these attributes are also merged onto the lead's stored profile, which requires the write:leads scope.

object

Company attributes. Scored against the account ruleset. When supplied, a company (account) is resolved-or-created and the lead is linked to it, which requires the write:accounts scope. The account is matched in this order: external_id (CRM company id) if provided, else domain, else name. The remaining attributes (industry, employees, revenue, ...) are merged onto the account.

Responses

Request samples

Content type
application/json
Example
{
  • "external_id": "linkedin:12345",
  • "idempotency_key": "n8n-exec-abc",
  • "source": "n8n",
  • "event": {
    }
}

Response samples

Content type
application/json
Example
{
  • "external_id": "linkedin:12345",
  • "lead_id": "0190d8e2-5a6b-7c3d-9e2f-1a2b3c4d5e6f",
  • "account_id": null,
  • "idempotency_key": "n8n-exec-abc",
  • "scored_at": "2026-06-06T12:00:01Z",
  • "disqualified": false,
  • "disqualified_reason": null,
  • "dimensions_scored": [
    ],
  • "enriched": {
    },
  • "cached": false,
  • "engagement": {
    },
  • "profile": {
    }
}

List active hard-DQ rules with current match counts

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get research-backed half-life suggestions

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.

Authorizations:
bearerAuth
query Parameters
dimension
string
Default: "all"
Enum: "engagement" "all"

Limit results to the engagement dimension. all is an alias for engagement. Profile, account, and deal are not event-sourced and return 400 if specified.

Responses

Response samples

Content type
application/json
{
  • "eligible_count": 0,
  • "ineligible_count": 0,
  • "suggestions": [
    ]
}

Bulk-apply research-backed half-life defaults

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
rule_ids
required
Array of strings <uuid> non-empty [ items <uuid > ]

Rule IDs to apply research defaults to. Must be non-empty.

Responses

Request samples

Content type
application/json
{
  • "rule_ids": [
    ]
}

Response samples

Content type
application/json
{
  • "applied_count": 0,
  • "skipped_count": 0,
  • "results": [
    ]
}

Calibration readiness for the active OU

Reports how close the active Organizational Unit is to producing scoring weight suggestions from sales outcomes. Powers the readiness strip on the calibration review card (Configure > Scoring).

It returns the number of qualifying logged outcomes in the look-back window, the 30-outcome floor that unlocks suggestions, the scored-lead cohort and its 50-lead floor, how many new outcomes have been logged since calibration last ran, and when it last ran.

When the OU has no conversion definition configured, a zero-state response is returned with the standard floors.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "conversions_in_window": 22,
  • "floor": 30,
  • "cohort_size": 140,
  • "cohort_floor": 50,
  • "new_dispositions_since_last_run": 6,
  • "last_run_at": "2026-06-09T07:00:00Z",
  • "floor_crossed_notified_at": null,
  • "progress_nudged_at": "2026-06-02T07:00:00Z"
}

Recalibrate the active OU now

Requests an immediate recalibration for the active Organizational Unit instead of waiting for the next weekly run. Powers the Recalibrate Now button on the calibration review card.

The request returns immediately; recalibration runs automatically in the background and updated suggestions appear on the calibration review page when it finishes. The OU must have a conversion definition configured.

Authorizations:
bearerAuthbasicAuth

Responses

Get per-rule calibration (engagement)

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.
  • insufficient_conversions — the conversion definition is disposition-fed (sales_disposition or manual_label) and fewer than 30 qualifying conversions exist. Includes conversions_observed, conversions_required (30), and conversion_type.
  • 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).
Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>
ruleId
required
string <uuid>
query Parameters
force
string
Value: "1"

Pass force=1 to bypass cache and recompute all rules in the OU.

Responses

Response samples

Content type
application/json
{
  • "state": "no_conversion_definition",
  • "required_action": "set_definition_in_ou_settings",
  • "leads_scored": 0,
  • "leads_required": 0,
  • "conversions_observed": 0,
  • "conversions_required": 30,
  • "conversion_type": "sales_disposition",
  • "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": [
    ],
  • "computed_at": "2019-08-24T14:15:22Z",
  • "stale": true
}

Get per-rule calibration (profile)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>
ruleId
required
string <uuid>
query Parameters
force
string
Value: "1"

Responses

Response samples

Content type
application/json
{
  • "state": "no_conversion_definition",
  • "required_action": "set_definition_in_ou_settings",
  • "leads_scored": 0,
  • "leads_required": 0,
  • "conversions_observed": 0,
  • "conversions_required": 30,
  • "conversion_type": "sales_disposition",
  • "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": [
    ],
  • "computed_at": "2019-08-24T14:15:22Z",
  • "stale": true
}

Get per-rule calibration (account)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>
ruleId
required
string <uuid>
query Parameters
force
string
Value: "1"

Responses

Response samples

Content type
application/json
{
  • "state": "no_conversion_definition",
  • "required_action": "set_definition_in_ou_settings",
  • "leads_scored": 0,
  • "leads_required": 0,
  • "conversions_observed": 0,
  • "conversions_required": 30,
  • "conversion_type": "sales_disposition",
  • "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": [
    ],
  • "computed_at": "2019-08-24T14:15:22Z",
  • "stale": true
}

Get per-rule calibration (deal)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>
ruleId
required
string <uuid>
query Parameters
force
string
Value: "1"

Responses

Response samples

Content type
application/json
{
  • "state": "no_conversion_definition",
  • "required_action": "set_definition_in_ou_settings",
  • "leads_scored": 0,
  • "leads_required": 0,
  • "conversions_observed": 0,
  • "conversions_required": 30,
  • "conversion_type": "sales_disposition",
  • "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": [
    ],
  • "computed_at": "2019-08-24T14:15:22Z",
  • "stale": true
}

List ruleset calibrations (engagement)

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.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
  • "dimension": "engagement",
  • "conversion_definition_summary": {
    },
  • "runs": [
    ]
}

List ruleset calibrations (profile)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
  • "dimension": "engagement",
  • "conversion_definition_summary": {
    },
  • "runs": [
    ]
}

List ruleset calibrations (account)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
  • "dimension": "engagement",
  • "conversion_definition_summary": {
    },
  • "runs": [
    ]
}

List ruleset calibrations (deal)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
rulesetId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "ruleset_id": "ca688a19-2766-4b2c-aefa-28d16a464773",
  • "dimension": "engagement",
  • "conversion_definition_summary": {
    },
  • "runs": [
    ]
}

Apply calibration to rule (engagement)

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).
  • 409 insufficient_conversions — disposition-fed definition (sales_disposition or manual_label) re-checked at apply time and fewer than 30 qualifying conversions exist. This apply-time floor is the governance backstop: a cached suggestion computed before disposition volume dropped can render but can never become a weight. No weight is written.
Authorizations:
bearerAuth
path Parameters
ruleId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "prior_weight": 0,
  • "new_weight": 0,
  • "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}

Apply calibration to rule (profile)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
ruleId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "prior_weight": 0,
  • "new_weight": 0,
  • "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}

Apply calibration to rule (account)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
ruleId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "prior_weight": 0,
  • "new_weight": 0,
  • "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}

Apply calibration to rule (deal)

Identical semantics to the engagement variant. See that endpoint for full documentation.

Authorizations:
bearerAuth
path Parameters
ruleId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "prior_weight": 0,
  • "new_weight": 0,
  • "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}

Triggers

List pattern/frequency triggers (OU-scoped)

Lists pattern triggers (including frequency counts) for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create pattern trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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>

Responses

Request samples

Content type
application/json
{
  • "trigger_id": "string",
  • "name": "string",
  • "description": "string",
  • "active": true,
  • "window_seconds": 0,
  • "conditions": [
    ],
  • "webhook_url": "string",
  • "emails": [
    ],
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Response samples

Content type
application/json
{
  • "trigger_id": "string",
  • "name": "string",
  • "description": "string",
  • "active": true,
  • "window_seconds": 0,
  • "conditions": [
    ],
  • "webhook_url": "string",
  • "emails": [
    ],
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update pattern trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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>

Responses

Request samples

Content type
application/json
{
  • "trigger_id": "string",
  • "name": "string",
  • "description": "string",
  • "active": true,
  • "window_seconds": 0,
  • "conditions": [
    ],
  • "webhook_url": "string",
  • "emails": [
    ],
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Delete pattern trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List notification failures (OU-scoped, cursor-paginated)

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "next_cursor": "string",
  • "total_count": 0
}

List notification channels (OU-scoped)

Returns all saved notification channels for the active Organizational Unit. Channels can be referenced when creating Milestone or Sequence Triggers.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create notification channel (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string

Display name for the channel

type
required
string
Enum: "slack" "teams" "webhook" "email"
required
object

Type-specific configuration fields

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "type": "slack",
  • "config": {
    }
}

Update notification channel (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
string
type
string
Enum: "slack" "teams" "webhook" "email"
object

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "type": "slack",
  • "config": {
    }
}

Delete notification channel (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Channel health summary (OU-scoped, 24-hour + 7-day window)

Returns a health summary for a single notification channel covering both a 24-hour window (delivered_24h, failed_24h, status) and a 7-day window (failure_count_7d, last_failure_at, last_error, is_healthy, permanent_failure). 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: currently always 0. The successful-delivery counter is a follow-up; until it ships, statuses green and amber (which require a non-zero delivered count) are unreachable. The meaningful states today are gray (no failures recorded) and red (at least one failure recorded with no tracked deliveries). The 7-day fields are the primary signal for the UI badge — they capture the "Bot not in channel — Fix" red state (permanent_failure) and the "had a transient blip" amber state (failure_count_7d > 0, permanent_failure=false).

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string <uuid>

Notification channel UUID

Responses

Response samples

Content type
application/json
{
  • "channel_id": "bbe8aa76-a4bb-46f6-a785-df8e831cc459",
  • "delivered_24h": 0,
  • "failed_24h": 0,
  • "failure_count_7d": 0,
  • "last_failure_at": "2019-08-24T14:15:22Z",
  • "last_error": "string",
  • "is_healthy": true,
  • "permanent_failure": true,
  • "status": "green"
}

Send a test notification through a notification channel (admin-only)

Sends a one-off "test" message through the configured channel so an administrator can confirm end-to-end delivery without firing a real trigger. Slack channels post a real chat.postMessage, webhook channels receive a signed JSON ping, and Teams returns 501 (test sends for Teams are not implemented yet — fire a real trigger or contact support). Every attempt — success or failure — writes an audit_logs row with extra.action="notification_channel_tested" so admins can see who pinged what when. Admin-only at the route layer; non-admins receive 403.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string <uuid>

Notification channel UUID

Request Body schema: application/json
optional

No request body. The endpoint takes the channel UUID from the path and the actor from the session.

object

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "ok": true,
  • "message_ts": "string",
  • "channel_id": "string",
  • "channel_type": "slack",
  • "error": "string",
  • "message": "string"
}

List milestone triggers (OU-scoped)

Lists milestone triggers configured for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create milestone trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "event_type": "string",
  • "score_threshold": 0,
  • "webhook_url": "string",
  • "emails": [
    ],
  • "email_subject": "string",
  • "email_preheader": "string",
  • "email_message": "string"
}

Response samples

Content type
application/json
{
  • "trigger_id": "string",
  • "org_id": "string",
  • "event_type": "string",
  • "score_threshold": 0,
  • "webhook_url": "string",
  • "emails": [
    ],
  • "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"
}

Update milestone trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "event_type": "string",
  • "score_threshold": 0,
  • "webhook_url": "string",
  • "emails": [
    ],
  • "email_subject": "string",
  • "email_preheader": "string",
  • "email_message": "string"
}

Delete milestone trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Get health for a milestone trigger (OU-scoped)

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).

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Milestone trigger ID

Responses

Response samples

Content type
application/json
{
  • "delivered_24h": 0,
  • "failed_24h": 3,
  • "last_failure_at": "2026-05-12T01:12:13Z",
  • "last_error": "connection timeout after 30s",
  • "status": "red",
  • "recent_attempts": [
    ]
}

Simulate a milestone trigger (OU-scoped)

Test a milestone trigger against a specific lead or scan historical data. Returns whether the trigger would fire and which leads match.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
lead_id
string

Specific lead to test (optional)

days
integer
Default: 30

Days to look back

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "days": 30
}

Response samples

Content type
application/json
{
  • "would_fire": true,
  • "matched_leads": [
    ],
  • "total_matches": 0,
  • "message": "string"
}

List emitted milestone events (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Export milestone events (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Sequences

List sequence triggers (OU-scoped)

Lists time- or order-based sequence triggers for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create sequence trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "event_types": [
    ],
  • "window_seconds": 0,
  • "window_unit": "seconds",
  • "ordered": true,
  • "webhook_url": "string",
  • "emails": [
    ],
  • "email_subject": "string",
  • "email_preheader": "string",
  • "email_message": "string"
}

Response samples

Content type
application/json
{
  • "trigger_id": "string",
  • "org_id": "string",
  • "unit_id": "string",
  • "name": "string",
  • "event_steps": [
    ],
  • "window_seconds": 0,
  • "window_unit": "seconds",
  • "ordered": true,
  • "fire_mode": "once",
  • "profile_filters": [
    ],
  • "lead_attribute_filters": [
    ],
  • "webhook_url": "string",
  • "emails": [
    ],
  • "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"
}

Update sequence trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "event_types": [
    ],
  • "window_seconds": 0,
  • "window_unit": "seconds",
  • "ordered": true,
  • "webhook_url": "string",
  • "emails": [
    ],
  • "email_subject": "string",
  • "email_preheader": "string",
  • "email_message": "string"
}

Delete sequence trigger (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Get health for a sequence trigger (OU-scoped)

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).

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Sequence trigger ID

Responses

Response samples

Content type
application/json
{
  • "delivered_24h": 0,
  • "failed_24h": 3,
  • "last_failure_at": "2026-05-12T01:12:13Z",
  • "last_error": "connection timeout after 30s",
  • "status": "red",
  • "recent_attempts": [
    ]
}

Simulate a sequence trigger (OU-scoped)

Test a sequence trigger against a specific lead or scan historical data. Returns whether the trigger would fire and which leads match.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
lead_id
string

Specific lead to test (optional)

days
integer
Default: 30

Days to look back

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "days": 30
}

Response samples

Content type
application/json
{
  • "would_fire": true,
  • "matched_leads": [
    ],
  • "total_matches": 0,
  • "message": "string"
}

List emitted sequence events (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Export sequence events (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

OrgUnits

List organization units for current user with organization info

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "units": [
    ],
  • "organization": {
    }
}

Create organization unit

Authorizations:
bearerAuth
Request Body schema: application/json
required
name
required
string

Responses

Request samples

Content type
application/json
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "unit_id": "string",
  • "name": "string",
  • "slug": "string"
}

Update organization unit

Authorizations:
bearerAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string

Responses

Request samples

Content type
application/json
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "unit_id": "string",
  • "name": "string",
  • "slug": "string"
}

Set active Organization Unit (OU)

Validates membership and sets the activeOu cookie. Returns OU headers for convenience.

Authorizations:
bearerAuth
Request Body schema: application/json
required
ouId
required
string

The unit_id to activate for the current session

Responses

Request samples

Content type
application/json
{
  • "ouId": "string"
}

List organization members

Lists members of the current organization. Results are organization-scoped.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create organization member

Authorizations:
bearerAuth
Request Body schema: application/json
required
first_name
required
string
last_name
required
string
email
required
string <email>
password
required
string <password>
role
required
string

Responses

Request samples

Content type
application/json
{
  • "first_name": "string",
  • "last_name": "string",
  • "email": "user@example.com",
  • "password": "pa$$word",
  • "role": "string"
}

Response samples

Content type
application/json
{
  • "org_member_id": "string",
  • "first_name": "string",
  • "last_name": "string",
  • "email": "user@example.com",
  • "role": "string"
}

Update organization member

Authorizations:
bearerAuth
path Parameters
id
required
string
Request Body schema: application/json
required
first_name
string
last_name
string
email
string <email>
role
string

Responses

Request samples

Content type
application/json
{
  • "first_name": "string",
  • "last_name": "string",
  • "email": "user@example.com",
  • "role": "string"
}

Delete organization member

Authorizations:
bearerAuth
path Parameters
id
required
string

Responses

Manually set a member's Slack user identifier

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.

Authorizations:
bearerAuth
path Parameters
org_member_id
required
string

Identifier of the target member.

Request Body schema: application/json
required
slack_user_id
required
string^U[A-Z0-9]+$

Slack user identifier. Must begin with U followed by uppercase letters and digits.

Responses

Request samples

Content type
application/json
{
  • "slack_user_id": "U012AB3CD"
}

OUMemberships

List OU memberships

Lists members assigned to the specified OU with OU-scoped roles. Requires caller to be a member of that OU.

Authorizations:
bearerAuth
path Parameters
id
required
string

OU ID (unit_id)

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Assign member to OU

Assigns a member to the specified OU with a role. Idempotent. Requires OU role Owner or Operator.

Authorizations:
bearerAuth
path Parameters
id
required
string

OU ID (unit_id)

Request Body schema: application/json
required
org_member_id
required
string
role
string
Default: "Viewer"
Enum: "Owner" "Operator" "Viewer"

Responses

Request samples

Content type
application/json
{
  • "org_member_id": "string",
  • "role": "Owner"
}

Update OU membership role (Owner/Operator required)

Authorizations:
bearerAuth
path Parameters
id
required
string
memberId
required
string
Request Body schema: application/json
required
role
required
string
Enum: "Owner" "Operator" "Viewer"

Responses

Request samples

Content type
application/json
{
  • "role": "Owner"
}

Remove OU membership (Owner/Operator required)

Authorizations:
bearerAuth
path Parameters
id
required
string
memberId
required
string

Responses

Me

Get current rate limit configuration for caller

Returns whether rate limiting is enabled, the mode, keying policy, computed key for this caller, and numeric limits.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "enabled": true,
  • "mode": "observe",
  • "key_by": "org",
  • "key": "string",
  • "rps": 0,
  • "burst": 0,
  • "stage": "string"
}

Get current user's notification preferences

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "notifications_enabled": true,
  • "slack_user_id": "string",
  • "prefs": [
    ]
}

Update current user's notification preferences

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
notifications_enabled
boolean

Master toggle.

Array of objects

Responses

Request samples

Content type
application/json
{
  • "notifications_enabled": true,
  • "prefs": [
    ]
}

Response samples

Content type
application/json
{
  • "status": "ok"
}

Secrets

List API credentials

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create API credential pair (Service Account)

Creates an org-owned Service Account: a client_id / client_secret pair used with HTTP Basic auth for unattended automation (for example n8n).

Pass scopes to make the credential least-privilege: when scopes are set, the credential can only reach routes covered by those scopes (every other token-gated route returns 403 insufficient_scope). Omit scopes (or send an empty list) for a legacy full-access credential. Fetch the available scopes from GET /settings/token-scopes.

Authorizations:
bearerAuth
Request Body schema: application/json
required
name
required
string <= 50 characters

Human-friendly label for this credential (1–50 chars)

scopes
Array of strings

Optional least-privilege scopes (read: / write:). Unknown scope strings are ignored. Omit for full access.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "secret_id": "string",
  • "client_id": "string",
  • "client_secret": "string",
  • "name": "string",
  • "scopes": [
    ],
  • "created_at": "2019-08-24T14:15:22Z"
}

Delete API credential

Authorizations:
bearerAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{
  • "error": "insufficient_scope",
  • "message": "This token is not authorized for write:leads"
}

Stream

Server-sent events stream

SSE stream of score updates, surge events, and newly ingested events.

OU scoping:

  • Prefer passing ouId as a query param to receive only events for that OU.
  • If omitted, the server will attempt to infer an OU from the activeOu cookie.

Note: This endpoint is currently unauthenticated.

query Parameters
ouId
string

Organization Unit (OU) ID to scope the stream.

Responses

Response samples

Content type
text/event-stream
event: score_update
data: {"lead_id":"ld_123","delta":5}

Usage

Usage metrics (OU/org scoped)

Returns current-month event usage, billing limits, and overage information for the organization.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "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"
}

Billing webhook receiver

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.

Request Body schema: application/json
required
type
string

Event type (e.g., subscription.created, subscription.updated)

data
object

Event payload (varies by type)

Responses

Request samples

Content type
application/json
{
  • "type": "string",
  • "data": { }
}

Response samples

Content type
application/json
{
  • "received": true
}

Surge

Surge metrics summary for an OU

Returns aggregated surge metrics for the specified organization unit within a time range. Requires authentication and an active organization; OU membership is enforced.

Authorizations:
bearerAuth
path Parameters
ouId
required
string

Organization Unit ID to scope the results.

query Parameters
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 1h.

channel
string

Optional channel filter (e.g., 'web', 'email', 'slack').

Responses

Response samples

Content type
application/json
{
  • "ou_id": "string",
  • "start": "2019-08-24T14:15:22Z",
  • "end": "2019-08-24T14:15:22Z",
  • "interval": "15m",
  • "totals": {
    },
  • "peak": {
    },
  • "channels": [
    ],
  • "series": [
    ]
}

Admin

Backfill account mapping and profile scoring (OU-scoped)

Runs account/profile mapping and recalculates profile scores for all leads in the active OU.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "leads_processed": 0,
  • "accounts_linked": 0,
  • "accounts_created": 0,
  • "profile_scores_updated": 0
}

Backfill event metadata accountId (OU-scoped)

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "events_scanned": 0,
  • "events_updated": 0,
  • "leads_without_account": 0
}

Apply profile field mappings to existing leads (OU-scoped)

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.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "leads_processed": 0,
  • "leads_updated": 0
}

Seed sample data into the active OU

Runs the seed script in non-interactive mode for the current org and active OU.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "message": "string",
  • "output": "string"
}

Wipe sample data from the active OU

Deletes records where source=seed or created_by=seed (org+OU scoped). Returns counts per delete operation.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{ }

List audit logs (OU-scoped)

Returns recent audit log entries for the active OU with optional filters and sorting.

Authorizations:
bearerAuth
query Parameters
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)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "limit": 0,
  • "offset": 0
}

Settings

Get Slack app configuration (org-level)

Returns whether Slack app credentials are configured for the current organization.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "configured": true,
  • "client_id": "string",
  • "has_signing_secret": true,
  • "has_oauth_client_secret": true
}

Set Slack app configuration (org-level)

Saves the Slack app credentials for the current organization. The Client Secret (oauth_client_secret) is used when connecting your workspace; the Signing Secret (signing_secret) verifies interactive button clicks. Both come from your Slack app's Basic Information > App Credentials page and are different values. Send an empty string (or omit a field) to keep its previously saved value.

Authorizations:
bearerAuth
Request Body schema: application/json
required
client_id
required
string
signing_secret
string

Verifies interactive button clicks. Empty keeps the saved value.

oauth_client_secret
string

Used in the workspace connection flow. Empty keeps the saved value.

client_secret
string

Deprecated alias for signing_secret, kept for older clients.

Responses

Request samples

Content type
application/json
{
  • "client_id": "string",
  • "signing_secret": "string",
  • "oauth_client_secret": "string",
  • "client_secret": "string"
}

Analyze a website and propose page-view scoring rules

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
url
required
string

Public website URL to analyze. Scheme is added automatically if omitted.

Responses

Request samples

Content type
application/json

Response samples

Content type
application/json
{
  • "domain": "example.com",
  • "fetched_url": "string",
  • "page_count": 0,
  • "skipped_urls": 0,
  • "source": "sitemap",
  • "categories": [
    ],
  • "proposed_rules": [
    ]
}

List available token scopes

Returns the full least-privilege scope taxonomy (read: / write:) with human-readable labels and descriptions. The same list powers the scope selector shown when creating a Personal Access Token or a Service Account, so the available scopes never drift from what the API enforces.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "scopes": [
    ]
}

Create a Personal Access Token

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
name
required
string [ 1 .. 100 ] characters

Descriptive label for the token (1–100 characters)

scopes
Array of strings

Optional least-privilege scopes (read: / write:). When scopes are set, the token can only reach routes those scopes cover; any other token-gated route returns 403 insufficient_scope. Omit for a full-access token (the token still inherits the user's role and OU access). Unknown scope strings are ignored. Fetch the available scopes from GET /settings/token-scopes.

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.

Responses

Request samples

Content type
application/json
{
  • "name": "MCP Server - Laptop",
  • "scopes": [
    ],
  • "expires_at": "2027-01-01T00:00:00Z"
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "name": "string",
  • "token": "kbn_pat_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  • "token_prefix": "kbn_pat_a1b2c3d4",
  • "scopes": [
    ],
  • "created_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z"
}

List Personal Access Tokens

Returns all Personal Access Tokens for the authenticated user. Token values are never included in this response — only metadata for managing tokens.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Revoke a Personal Access Token

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.

Authorizations:
bearerAuth
path Parameters
id
required
string

The token ID (from POST /settings/tokens or GET /settings/tokens)

Responses

List event types with OU visibility and counts

Returns organization event types with hidden flag and per-OU event counts.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Set OU visibility for an event type

path Parameters
eventType
required
string
Request Body schema: application/json
required
hidden
boolean
max_processing_scope
string
Enum: "observe" "decide" "activate"

Ceiling for event processing in this OU; does not imply execution.

Responses

Request samples

Content type
application/json
{
  • "hidden": true,
  • "max_processing_scope": "observe"
}

Dry-run delete of all events for an event type (OU)

path Parameters
eventType
required
string

Responses

Response samples

Content type
application/json
{
  • "events_count": 0,
  • "event_scores_count": 0
}

Delete all events for an event type in the active OU

path Parameters
eventType
required
string

Responses

Response samples

Content type
application/json
{
  • "events_deleted": 0,
  • "event_scores_deleted": 0
}

Get OU Slack integration status

Returns whether the active OU is connected to a Slack workspace and basic metadata.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "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"
}

Begin Slack installation

Redirects the browser to Slack's OAuth installation URL using organization-specific app credentials.

Authorizations:
bearerAuth

Responses

Initiate Slack installation

Creates a short-lived, single-use OAuth state for the active OU and returns Slack's authorize URL.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "authorize_url": "string"
}

Slack OAuth callback

Handles Slack OAuth exchange and persists the OU connection, then redirects back to the Integrations page.

Responses

Disconnect OU Slack integration

Authorizations:
bearerAuth

Responses

List Slack channels for the connected workspace

Proxies Slack conversations.list and returns the upstream response. Requires the OU to be connected to Slack.

Authorizations:
bearerAuth
query Parameters
types
string
Example: types=public_channel,private_channel

Responses

Response samples

Content type
application/json
{
  • "ok": true,
  • "channels": [
    ],
  • "response_metadata": {
    }
}

List Slack users for the connected workspace

Proxies Slack users.list and returns the upstream response. Requires the OU to be connected to Slack.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "ok": true,
  • "members": [
    ],
  • "response_metadata": {
    }
}

Set default Slack notification target for the active OU

Persists the default Slack target (channel or user) for notifications.

Authorizations:
bearerAuth
Request Body schema: application/json
required
kind
required
string
Enum: "channel" "user"
id
required
string

Responses

Request samples

Content type
application/json
{
  • "kind": "channel",
  • "id": "string"
}

Send a test Slack notification to the selected target

Sends a simple test message to the provided channel or user for the active OU. If kind=user, opens a DM first.

Authorizations:
bearerAuth
Request Body schema: application/json
required
kind
required
string
Enum: "channel" "user"
id
required
string
text
string

Optional custom message

Responses

Request samples

Content type
application/json
{
  • "kind": "channel",
  • "id": "string",
  • "text": "string"
}

Response samples

Content type
application/json
{
  • "message": "string"
}

Get the Slack publish-notification opt-in flag for the active OU

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "enabled": true
}

Set the Slack publish-notification opt-in flag for the active OU

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
enabled
required
boolean

Responses

Request samples

Content type
application/json
{
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "enabled": true
}

Get conversion definition

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "definition": {
    },
  • "cold_start_state": {
    },
  • "hubspot_sync_freshness": {
    }
}

Create or replace conversion definition

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.
  • sales_disposition counts leads marked accepted_sql (Qualified) or closed_won within the look-back window (closed-loop disposition feedback, ADR-0066).
  • For 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.
  • For 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).

Every successful PUT discards the OU's cached calibration runs so future reads recompute under the new definition.

Authorizations:
bearerAuth
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "conversion_type": "closed_won",
  • "deal_stages": [
    ],
  • "event_type_id": 0,
  • "engagement_persistence_days": 14,
  • "lookback_days": 90
}

Response samples

Content type
application/json
{
  • "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": [
    ],
  • "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"
}

Delete conversion definition

Removes the active OU's conversion definition. Returns 404 if none was configured.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "error": "rule_not_found"
}

Get OU surge session policy

Returns the OU-scoped session-based surge multiplier policy for the active OU. If none exists, returns Standard defaults.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "org_id": "string",
  • "unit_id": "string",
  • "mode": "off",
  • "bands": [
    ],
  • "idle_reset_seconds": 1,
  • "multiplier_cap": 1
}

Upsert OU surge session policy

Creates or updates the session-based surge multiplier policy for the active OU.

Authorizations:
bearerAuth
Request Body schema: application/json
required
mode
string
Enum: "off" "standard" "gentle" "custom"
Array of objects
idle_reset_seconds
integer >= 1
multiplier_cap
number [ 1 .. 3 ]

Responses

Request samples

Content type
application/json
{
  • "mode": "off",
  • "bands": [
    ],
  • "idle_reset_seconds": 1,
  • "multiplier_cap": 1
}

Get disposition nudge settings for the active OU

Returns the per-OU settings for the weekly "leads awaiting disposition" Slack reminder and the calibration payoff message. When no settings have been saved, the enabled defaults are returned.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
{
  • "enabled": true,
  • "payoff_enabled": true,
  • "cadence_days": 1,
  • "min_age_days": 365,
  • "min_score": 0,
  • "max_leads_per_owner": 1
}

Update disposition nudge settings for the active OU

Creates or updates the disposition nudge settings for the active Organizational Unit. Every field is optional; only the fields you send are changed, and the rest keep their current values.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
enabled
boolean

Turn the awaiting-disposition reminder on or off.

payoff_enabled
boolean

Turn the calibration payoff and readiness messages on or off.

cadence_days
integer [ 1 .. 365 ]

How often the reminder is sent, in days.

min_age_days
integer [ 0 .. 365 ]

How long a lead must have had an owner before it appears.

min_score
integer >= 0

Only leads scoring at or above this value are included.

max_leads_per_owner
integer [ 1 .. 50 ]

The most leads listed in one owner's reminder.

Responses

Request samples

Content type
application/json
{
  • "enabled": true,
  • "cadence_days": 7,
  • "min_age_days": 3,
  • "min_score": 25,
  • "max_leads_per_owner": 8
}

Response samples

Content type
application/json
{
  • "enabled": true,
  • "payoff_enabled": true,
  • "cadence_days": 1,
  • "min_age_days": 365,
  • "min_score": 0,
  • "max_leads_per_owner": 1
}

Get Slack identity mapping status for the active OU

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).

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "total": 0,
  • "mapped": 0
}

Run the Slack identity sync for the active OU

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "members_total": 0,
  • "matched": 0,
  • "no_match": 0,
  • "errors": 0
}

Public

Unauthenticated endpoints that serve publicly shareable content. These endpoints do not require an API key or session cookie.

Retrieve a shared score explanation

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.

path Parameters
token
required
string

Share token returned by POST /leads/{id}/share-explain

Responses

Response samples

Content type
application/json
{
  • "lead_name": "string",
  • "score": 0,
  • "top_drivers": [
    ],
  • "snapshot": [
    ],
  • "decay_applied": 0,
  • "range_hours": 0
}

HubSpot

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.

Update engagement type preferences

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "engagement_types": [
    ],
  • "include_engagement_history": false
}

Response samples

Content type
application/json
{
  • "engagement_types": [
    ],
  • "include_engagement_history": true
}

Get engagement sync status

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "engagement_types": [
    ],
  • "include_engagement_history": true,
  • "engagement_history_synced": true,
  • "engagement_history_synced_at": "2019-08-24T14:15:22Z"
}

Get disposition writeback configuration

Returns the disposition writeback configuration for the active Organizational Unit. Disposition writeback updates a HubSpot contact's lifecycle stage and lead status when a rep logs a sales outcome on the matched lead. Off by default; when enabled, comes seeded with sensible default mappings.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "enabled": true,
  • "mappings": {
    }
}

Update disposition writeback configuration

Enables or disables disposition writeback and sets the per-disposition mapping to HubSpot lifecycle stage and lead status. Mapped values are accepted as-is; the writeback worker only ever moves a contact's lifecycle stage forward and never reverts a property when a disposition is cleared.

Authorizations:
bearerAuth
Request Body schema: application/json
required
enabled
boolean

Whether outbound disposition writeback is active for this OU.

object

Map keyed by kenbun disposition value to its HubSpot property target.

Responses

Request samples

Content type
application/json
{
  • "enabled": true,
  • "mappings": {
    }
}

Get disposition writeback dropdown options

Returns the connected HubSpot portal's actual lifecycle stage and lead status option lists (including custom stages), alongside the current configuration and the default mapping. Use this to render the writeback mapping dropdowns so they match the customer's portal rather than guessing values.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "lifecycle_stages": [
    ],
  • "lead_statuses": [
    ],
  • "config": {
    },
  • "defaults": {
    }
}

Import historical HubSpot data

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.

Authorizations:
bearerAuth
Request Body schema: application/json
optional
include_contacts
boolean

Whether to import historical contacts. Defaults to true when the field is omitted from the request body.

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 include_engagement_history is true. If omitted, all enabled types are imported.

force
boolean

When true, re-imports engagement history even if it was previously imported. Has no effect on contact imports (contacts always use upsert).

Responses

Request samples

Content type
application/json
{
  • "include_contacts": true,
  • "include_engagement_history": true,
  • "engagement_types": [
    ],
  • "force": false
}

Response samples

Content type
application/json
{
  • "status": "queued",
  • "message": "Historical import started",
  • "queued": [
    ]
}

Get HubSpot connection status

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.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "connected": true,
  • "app_mode": "shared",
  • "has_credentials": true,
  • "portal_id": "string",
  • "last_synced_at": "2019-08-24T14:15:22Z"
}

Start the HubSpot OAuth handshake

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:

  • If customer-supplied credentials are saved on the connection (app_mode: byo), the URL is built using those credentials.
  • Otherwise the URL is built using the kenbun-managed shared app (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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{}

Save customer-supplied HubSpot OAuth credentials (Bring Your Own App)

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "client_id": "string",
  • "client_secret": "string"
}

Response samples

Content type
application/json
{
  • "status": "saved",
  • "app_mode": "byo"
}

Clear customer-supplied HubSpot OAuth credentials

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "cleared",
  • "app_mode": "shared"
}

Onboarding

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.

Guided setup checklist status (OU-scoped)

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).

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "steps": [
    ],
  • "all_complete": false,
  • "completed_count": 1,
  • "total_count": 3
}

Account

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.

Look up account by domain or name

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
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.

Responses

Response samples

Content type
application/json
Example
{
  • "account_id": "acct_abc123",
  • "name": "Acme Corporation",
  • "domain": "acme.com"
}

Fuzzy search accounts by name similarity

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.

Authorizations:
bearerAuthbasicAuth
query Parameters
name
required
string

Company name to search for (e.g., "Salesforce LLC").

Responses

Response samples

Content type
application/json
Example
{
  • "matches": [
    ]
}

List accounts aggregated by OU

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).

Authorizations:
bearerAuthbasicAuth
query Parameters
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).

Responses

Response samples

Content type
application/json
{
  • "accounts": [
    ],
  • "total": 1,
  • "page": 1,
  • "limit": 25
}

Batch delete/unlink accounts

Unlinks leads in the active OU from the given accounts and deletes account records that are no longer referenced by any lead.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
ids
Array of strings

Responses

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

Get account detail

path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{
  • "account_id": "string",
  • "org_id": "string",
  • "domain": "string",
  • "name": "string",
  • "metadata": { },
  • "top_score": 0,
  • "leads": [
    ],
  • "recent_events": [
    ]
}

Update account metadata

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Account ID

Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{}

Merge source account into target account

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

The source account ID to be archived

Request Body schema: application/json
required
target_id
required
string

The ID of the target account that will receive all leads and deals

Responses

Request samples

Content type
application/json
{
  • "target_id": "acct_def456"
}

Response samples

Content type
application/json
{
  • "leads_reassigned": 8,
  • "deals_reassigned": 3
}

Get aggregated Top-3 scoring factors across the buying committee

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.

Authorizations:
bearerAuthbasicAuth
path Parameters
accountID
required
string

The account ID

Responses

Response samples

Content type
application/json
{
  • "account_id": "string",
  • "summary": "string",
  • "factors": [
    ],
  • "contributing_lead_count": 0,
  • "total_contact_count": 0,
  • "mostly_disqualified": true
}

Test an account scoring rule against an account (dry run)

Evaluates an account scoring rule against a specific account without modifying production scores.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
lead_id
required
string

The lead whose account to test against

required
object

The account rule configuration to evaluate

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "rule": {
    }
}

Response samples

Content type
application/json
{
  • "matches": true,
  • "reason": "string",
  • "current_score": 0,
  • "projected_score": 0,
  • "matching_value": "string"
}

List account rule sets (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create account rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
enabled
boolean
is_primary
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "enabled": true,
  • "is_primary": false
}

Response samples

Content type
application/json
{
  • "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"
}

Update account rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
enabled
boolean
is_primary
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "enabled": true,
  • "is_primary": false
}

Delete account rule set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List account rules in a set (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create account rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "account_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "ui_order": 0,
  • "rule_type": "add_points",
  • "conditions": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "ruleset_id": "string",
  • "account_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "half_life_days": 1,
  • "rule_type": "add_points",
  • "conditions": {
    },
  • "ui_order": 0,
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update account rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
ruleId
required
string
Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "account_property": "string",
  • "condition": "string",
  • "comparison_value": "string",
  • "weight": 0,
  • "ui_order": 0,
  • "rule_type": "add_points",
  • "conditions": {
    }
}

Delete account rule (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
ruleId
required
string

Responses

Get account mapping change history (OU-scoped)

Returns the audit log of all account mapping changes — creates, updates, and deletes — for the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List distinct account metadata property keys (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • "string"
]

List account field mappings (OU-scoped)

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create account field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
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 "_list"

Responses

Request samples

Content type
application/json
{
  • "source_field": "string",
  • "account_property": "string",
  • "update_behavior": "always_latest"
}

Response samples

Content type
application/json
{
  • "id": "string",
  • "source_field": "string",
  • "account_property": "string",
  • "update_behavior": "always_latest",
  • "created_at": "2019-08-24T14:15:22Z"
}

Update account field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
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 "_list"

Responses

Request samples

Content type
application/json
{
  • "source_field": "string",
  • "account_property": "string",
  • "update_behavior": "always_latest"
}

Delete account field mapping (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Get buying committee for an account

Returns the buying committee members for an account, including their roles, engagement scores, and activity metrics.

Authorizations:
bearerAuth
path Parameters
accountId
required
string <uuid>

Account identifier

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Add a member to the buying committee

Manually add a lead to an account's buying committee with a specific role. Manually added members are preserved during automatic role refresh.

Authorizations:
bearerAuth
path Parameters
accountId
required
string <uuid>
Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "role": "decision_maker",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "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"
}

Remove a member from the buying committee

Authorizations:
bearerAuth
path Parameters
accountId
required
string <uuid>
leadId
required
string <uuid>

Responses

Refresh auto-detected buying committee roles

Re-runs role inference for auto-detected members based on current engagement data. Manually assigned roles are preserved.

Authorizations:
bearerAuth
path Parameters
accountId
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Update a contact's buying committee role

Authorizations:
bearerAuth
path Parameters
accountId
required
string <uuid>
Request Body schema: application/json
required
lead_id
required
string
role
required
string
Enum: "decision_maker" "influencer" "champion" "kol" "other"
notes
string

Responses

Request samples

Content type
application/json
{
  • "lead_id": "string",
  • "role": "decision_maker",
  • "notes": "string"
}

Activation

Activation endpoints help a new workspace get started quickly: generate a realistic sample pipeline to explore the product, then remove it for a clean slate, and fire a single test event to watch a lead's score move in real time. Sample and test data are excluded from billing and usage. All endpoints require an authenticated session and an active Organizational Unit; org_id and unit_id are derived from your account context and are never read from the request body.

Get sample data status for the active OU

Returns whether the active Organizational Unit currently has a generated sample data batch, and whether the OU is "empty" (has no real, non-sample leads or events). The Generate Sample Data action is only offered for an empty OU.

org_id and unit_id are derived from your account context; they are never read from the request body.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
Example
{
  • "batch_exists": false,
  • "empty_ou": true,
  • "generated_at": null,
  • "summary": null
}

Generate sample data for the active OU

Generates a complete demo pipeline for the active Organizational Unit: a populated scoring configuration plus realistic leads, accounts, events, and a fired milestone. Generation runs in the background and the response returns immediately with 202 Accepted and a batch_id. Poll GET /sample-data/status to see the populated summary once generation finishes.

Generation is only allowed on an empty workspace and is idempotent: if the OU already has real leads/events, or a sample batch already exists, the request is rejected with 409 Conflict.

Sample events are recorded with source: sample_data and are excluded from billing and usage. The request takes no body; org_id and unit_id are derived from your account context and are never read from the request body.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "batch_id": "3f2a9c1e-5b4d-4e2a-9f7c-1a2b3c4d5e6f",
  • "status": "generating"
}

Remove sample data for the active OU

Removes every row generated by the sample data batch for the active Organizational Unit — both the demo scoring configuration and the demo leads, accounts, and events — returning the OU to a clean slate. The prior primary scoring ruleset (if any) is restored.

Returns the per-category counts of removed records. Returns 404 Not Found when there is no sample data to remove. The request takes no body; org_id and unit_id are derived from your account context and are never read from the request body.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "summary": {
    }
}

Fire a test event

Fires a single synthetic engagement event through real scoring and returns the score before and after, so you can watch a lead's engagement score move in real time. If the resulting score crosses an active milestone threshold, a trigger_fired alert is broadcast to the in-app live feed and trigger_fired is set in the response.

By default no external notification is sent. Set deliver_to_channel: true to also send a real test message to the OU's configured Slack channel, reusing the standard channel-test path. (Microsoft Teams test sends are not supported yet and return an delivery block with teams_test_unsupported.)

Test events are recorded with source: test and are excluded from billing and usage. org_id and unit_id are derived from your account context; any org_id/unit_id keys inside metadata are ignored.

Authorizations:
bearerAuth
Request Body schema: application/json
required
event_type
required
string

The event type to fire (e.g. "Form Submit", "Page View").

lead_id
string

Optional. The lead to apply the event to. When omitted, score_before and score_after are reported as 0 and no milestone can fire.

object

Optional event metadata (e.g. page path, form id). Any org_id/unit_id keys are ignored — scoping comes from your account context.

deliver_to_channel
boolean
Default: false

When true, also send a real test message to the OU's configured Slack channel. Defaults to false (in-app alert only). Teams channels are not supported yet.

Responses

Request samples

Content type
application/json
Example
{
  • "event_type": "Form Submit",
  • "lead_id": "ld_123",
  • "metadata": {
    }
}

Response samples

Content type
application/json
Example
{
  • "ok": true,
  • "lead_id": "ld_123",
  • "event_type": "Form Submit",
  • "score_before": 54,
  • "score_after": 84,
  • "score_delta": 30,
  • "trigger_fired": true,
  • "trigger_name": "Form Submission + 30 Points",
  • "explanation": "Score 84 crossed threshold 30 for trigger \"Form Submission + 30 Points\""
}

Deals

Test a deal scoring rule against a deal (dry run)

Evaluates a deal scoring rule against a specific deal without modifying production scores.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
deal_id
required
string

The deal to test the rule against

required
object

The deal rule configuration to evaluate

Responses

Request samples

Content type
application/json
{
  • "deal_id": "string",
  • "rule": {
    }
}

Response samples

Content type
application/json
{
  • "matches": true,
  • "reason": "string",
  • "current_score": 0,
  • "projected_score": 0,
  • "matching_value": "string"
}

Levels

Get engagement level configuration history (OU-scoped)

Returns snapshots of the engagement level configuration, saved each time a level is created, updated, or deleted.

Authorizations:
bearerAuthbasicAuth
query Parameters
ruleset_id
required
string

The ruleset ID to retrieve history for

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Revert engagement levels to a historical snapshot (OU-scoped)

Replaces the current engagement level configuration with a previously saved snapshot.

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
history_id
required
string

ID of the history entry to revert to

Responses

Request samples

Content type
application/json
{
  • "history_id": "string"
}

Get profile level configuration history (OU-scoped)

Returns snapshots of the profile level configuration, saved each time a level is created, updated, or deleted.

Authorizations:
bearerAuthbasicAuth
query Parameters
ruleset_id
required
string

Responses

Response samples

Content type
application/json
[
  • { }
]

Revert profile levels to a historical snapshot (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
history_id
required
string

Responses

Request samples

Content type
application/json
{
  • "history_id": "string"
}

Get account level configuration history (OU-scoped)

Returns snapshots of the account level configuration, saved each time a level is created, updated, or deleted.

Authorizations:
bearerAuthbasicAuth
query Parameters
ruleset_id
required
string

Responses

Response samples

Content type
application/json
[
  • { }
]

Revert account levels to a historical snapshot (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
history_id
required
string

Responses

Request samples

Content type
application/json
{
  • "history_id": "string"
}

List engagement levels (OU-scoped)

Lists configured engagement levels within the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create engagement level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Response samples

Content type
application/json
{
  • "stage_id": "st_hot",
  • "name": "Hot",
  • "min_score": 80,
  • "max_score": 1000
}

Update engagement level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Delete engagement level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List profile levels (OU-scoped)

Lists configured profile levels within the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create profile level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Response samples

Content type
application/json
{
  • "level_id": "string",
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0,
  • "org_id": "string",
  • "created_by": "string",
  • "updated_by": "string"
}

Update profile level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Delete profile level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

List account levels (OU-scoped)

Lists configured account levels within the active OU.

Authorizations:
bearerAuthbasicAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create account level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Response samples

Content type
application/json
{
  • "level_id": "string",
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0,
  • "org_id": "string",
  • "created_by": "string",
  • "updated_by": "string"
}

Update account level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string
Request Body schema: application/json
required
name
required
string
min_score
required
integer
max_score
required
integer

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "min_score": 0,
  • "max_score": 0
}

Delete account level (OU-scoped)

Authorizations:
bearerAuthbasicAuth
path Parameters
id
required
string

Responses

Get scoring settings

Returns scoring settings (organization-wide toggles plus the effective session idle timeout for the active OU).

Responses

Response samples

Content type
application/json
{
  • "allow_negative_scores": true,
  • "abm_enabled": true,
  • "session_timeout_minutes": 0
}

Update scoring settings

Updates scoring settings (organization-wide toggles plus per-OU session idle timeout for the active OU).

Request Body schema: application/json
required
allow_negative_scores
boolean
abm_enabled
boolean
session_timeout_minutes
integer

Responses

Request samples

Content type
application/json
{
  • "allow_negative_scores": true,
  • "abm_enabled": true,
  • "session_timeout_minutes": 0
}