Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt

Use this file to discover all available pages before exploring further.

GET /api/v1/customers//eligibility

Returns a detailed eligibility report for a customer across all active offers. For each offer, evaluates every qualification rule and contact policy, returning pass/fail with reasons.

Response

{
  "customerId": "CUST001",
  "customer": {
    "customer_id": "CUST001",
    "age": 35,
    "segment": "high_value"
  },
  "evaluatedAt": "2026-03-30T12:00:00.000Z",
  "summary": {
    "totalOffers": 25,
    "eligibleCount": 12,
    "ineligibleCount": 13,
    "failedQualification": 8,
    "blockedByContactPolicy": 3,
    "blockedBySchedule": 2,
    "noCreatives": 1
  },
  "offers": [
    {
      "offerId": "off_001",
      "offerName": "Platinum Card Upgrade",
      "offerKey": "platinum_upgrade",
      "category": "Credit Cards",
      "subCategory": "Premium",
      "priority": 90,
      "eligible": true,
      "primaryReason": "All rules passed",
      "score": 0.9,
      "rank": 1,
      "scheduleBlocked": false,
      "scheduleReason": null,
      "qualificationPassed": true,
      "failedRules": [],
      "passedRules": [
        {
          "ruleId": "qr_001",
          "ruleName": "High Value Segment",
          "ruleType": "segment_required",
          "scope": "global",
          "eligible": true,
          "reason": null
        }
      ],
      "allRuleResults": [],
      "contactPolicyBlocked": false,
      "blockedPolicies": [],
      "allPolicyResults": [],
      "hasCreatives": true,
      "creativeCount": 3
    },
    {
      "offerId": "off_002",
      "offerName": "Auto Loan Refinance",
      "offerKey": "auto_refi",
      "category": "Lending",
      "subCategory": null,
      "priority": 70,
      "eligible": false,
      "primaryReason": "Failed: Min Credit Score",
      "score": null,
      "rank": null,
      "scheduleBlocked": false,
      "scheduleReason": null,
      "qualificationPassed": false,
      "failedRules": [
        {
          "ruleId": "qr_005",
          "ruleName": "Min Credit Score",
          "ruleType": "attribute_condition",
          "scope": "category",
          "eligible": false,
          "reason": "credit_score < 720"
        }
      ],
      "passedRules": [],
      "allRuleResults": [],
      "contactPolicyBlocked": false,
      "blockedPolicies": [],
      "allPolicyResults": [],
      "hasCreatives": true,
      "creativeCount": 2
    }
  ]
}
Offers are sorted: eligible first (by score descending), then ineligible (by priority descending). Each eligible offer receives a rank (1-based); ineligible offers have rank: null.

Contact policy result objects

When a contact policy blocks an offer, the blockedPolicies array contains objects with:
FieldTypeDescription
policyIdstringContact policy ID
policyNamestringContact policy name
ruleTypestringfrequency_cap, cooldown, or time_window
blockedbooleanWhether this policy blocked the offer
reasonstringHuman-readable reason (e.g., "Daily limit reached (5/5)")

GET /api/v1/customers//profile

Returns a traced decision pipeline for a customer, showing the full evaluation funnel from all offers down to ranked results.

Response

{
  "customer": {
    "customer_id": "CUST001",
    "age": 35,
    "segment": "high_value",
    "tenure_months": 36
  },
  "pipeline": {
    "allOffers": [
      {
        "id": "off_001",
        "name": "Platinum Card Upgrade",
        "priority": 90,
        "category": "Credit Cards",
        "subCategory": "Premium",
        "mandatory": false
      }
    ],
    "afterQualification": [
      { "offerId": "off_001", "offerName": "Platinum Card Upgrade" }
    ],
    "qualificationRejections": [
      {
        "offerId": "off_002",
        "offerName": "Auto Loan Refinance",
        "policyName": "Min Credit Score",
        "policyId": "qr_005",
        "ruleType": "attribute_condition",
        "detail": {
          "type": "attribute_condition",
          "attribute": "credit_score",
          "operator": "gte",
          "expected": 720,
          "actual": 680
        }
      }
    ],
    "offersWithoutCreatives": [],
    "afterContactPolicy": [
      { "offerId": "off_001", "offerName": "Platinum Card Upgrade" }
    ],
    "contactPolicyRejections": [
      {
        "offerId": "off_003",
        "offerName": "Savings Account",
        "creativeId": "cr_010",
        "creativeName": "Email Variant A",
        "policyName": "Daily Frequency Cap",
        "policyId": "cp_001",
        "ruleType": "frequency_cap",
        "detail": {
          "type": "frequency_cap",
          "period": "daily",
          "max": 3,
          "actual": 3
        }
      }
    ],
    "rankedResults": [
      {
        "creativeId": "cr_001",
        "creativeName": "Email Hero",
        "offerId": "off_001",
        "offerName": "Platinum Card Upgrade",
        "category": "Credit Cards",
        "subCategory": "Premium",
        "channelType": "email",
        "channelName": "Marketing Email",
        "channelId": "ch_001",
        "templateType": "html",
        "weight": 80,
        "score": 0.72,
        "priority": 90,
        "rank": 1
      }
    ]
  },
  "interactionHistory": [
    {
      "id": "ih_001",
      "timestamp": "2026-03-28T10:30:00.000Z",
      "offerName": "Platinum Card Upgrade",
      "creativeName": "Email Hero",
      "channelId": "ch_001",
      "interactionType": "click",
      "outcomeTypeKey": "click",
      "direction": "outbound",
      "rank": 1
    }
  ],
  "summaries": [
    {
      "periodType": "alltime",
      "periodKey": "alltime",
      "customerId": "CUST001",
      "offerId": "off_001",
      "impressions": 12,
      "positive": 4,
      "negative": 1,
      "converts": 2
    }
  ]
}

Qualification rejection detail types

The detail object in qualificationRejections varies by rule type:
Rule TypeDetail Fields
segment_requiredrequired (string[]), actual (string[])
attribute_conditionattribute, operator, expected, actual
propensity_thresholdmodel, minScore, actualScore
recency_checkattribute, maxDays, actualDays

Contact policy rejection detail types

Rule TypeDetail Fields
frequency_capperiod, max, actual
cooldowncooldownHours, hoursSinceLast
budget_exhaustedbudgetField, threshold, actual
outcome_basedafterOutcome, suppressForDays, daysSince, lastOutcome
segment_exclusionexcludeSegments (string[]), matchedSegment
time_windowallowedDays, currentDay, startHour, endHour, currentHour
mutual_exclusionofferGroup (string[]), conflictingOfferId
category_suppressioncategoryId, subCategoryId, suppressionDays, daysSince, triggeringOfferId, suppressedUntil

POST /api/v1/customers//simulate

Runs the Recommend API internally for a customer and returns the full decision result including scores, rankings, and channel assignments. Always includes debug information.

Request Body

FieldTypeRequiredDescription
channelstringNoFilter by channel
placementstringNoFilter by placement
limitintegerNoMax results (default: 20)
flowIdstringNoDecision flow ID or key (alias: decisionFlowKey)

Response

{
  "customerId": "CUST001",
  "simulatedAt": "2026-03-30T12:00:00.000Z",
  "success": true,
  "channel": "email",
  "placement": "all",
  "flowId": "auto-resolved",
  "result": {
    "recommendations": [],
    "debug": {}
  }
}

Error Response

If the internal recommend call fails:
{
  "customerId": "CUST001",
  "simulatedAt": "2026-03-30T12:00:00.000Z",
  "error": "No active decision flow found",
  "success": false
}

GET /api/v1/customers//suppressions

Returns active suppressions for a customer with resolved offer names.

Response

{
  "data": [
    {
      "id": "sup_001",
      "scope": "offer",
      "scopeId": "off_001",
      "offerName": "Platinum Card Upgrade",
      "policyType": "frequency_cap",
      "reason": "Daily limit reached (5/5)",
      "triggerCount": 5,
      "expiresAt": "2026-04-01T00:00:00.000Z",
      "createdAt": "2026-03-30T10:00:00.000Z",
      "isActive": true
    }
  ]
}
FieldTypeDescription
scopestringSuppression scope (offer, category, global)
scopeIdstringID of the scoped entity
offerNamestring or nullResolved offer name (only when scope is offer)
policyTypestringContact policy type that triggered the suppression
triggerCountintegerNumber of times the suppression was triggered
expiresAtstringISO timestamp when the suppression expires
isActivebooleanWhether the suppression is currently active (expiresAt > now)

GET /api/v1/customers//summaries

Returns interaction summary aggregates for a specific customer, including per-offer breakdowns and rolled-up totals.

Query Parameters

ParameterTypeRequiredDescription
periodTypestringNoFilter: daily, weekly, monthly, alltime
periodKeystringNoSpecific period key (e.g., 2026-03-30, 2026-W13)
offerIdstringNoFilter by specific offer
channelIdstringNoFilter by specific channel

Response

{
  "customerId": "CUST001",
  "totals": {
    "impressions": 156,
    "positive": 42,
    "negative": 18,
    "neutral": 96,
    "converts": 12,
    "totalValue": 4800.50,
    "overallConversionRate": 0.0769
  },
  "byOffer": [
    {
      "offerId": "off_001",
      "offerName": "Platinum Card Upgrade",
      "impressions": 45,
      "positive": 15,
      "negative": 5,
      "converts": 4,
      "totalValue": 1200.00,
      "conversionRate": 0.0889,
      "lastOutcomeKey": "convert",
      "lastContactAt": "2026-03-28T10:30:00.000Z"
    }
  ],
  "raw": [
    {
      "periodType": "alltime",
      "periodKey": "alltime",
      "offerId": "off_001",
      "offerName": "Platinum Card Upgrade",
      "channelId": "ch_001",
      "impressions": 45,
      "positive": 15,
      "negative": 5,
      "neutral": 25,
      "converts": 4,
      "totalValue": 1200.00,
      "lastOutcomeKey": "convert",
      "lastContactAt": "2026-03-28T10:30:00.000Z",
      "direction": "outbound"
    }
  ],
  "meta": {
    "summaryCount": 12,
    "periodTypes": ["daily", "weekly", "alltime"],
    "queriedAt": "2026-03-30T12:00:00.000Z"
  }
}

DELETE /api/v1/customers/

Deletes all stored data for a customer. Supports GDPR right-to-erasure (DSAR) workflows. Deletes interaction history, interaction summaries, experiment assignments, and impressions in foreign-key-safe order.

Response

{
  "success": true,
  "deleted": {
    "interactionHistory": 142,
    "interactionSummary": 23,
    "experimentAssignments": 0,
    "impressions": 67
  }
}

Error codes

CodeReason
403Caller does not have admin role.
This permanently deletes customer data. This operation cannot be undone. An audit event is logged for every deletion.

DELETE /api/v1/customers//data

Scoped, GDPR-compliant deletion of customer data with a confirmation safeguard. The route at src/app/api/v1/customers/[customerId]/data/route.ts:24-122 requires the caller to set the X-Confirm-Delete header to the same customerId in the path — a missing or mismatched header returns 400 so a stray DELETE call cannot purge data by accident. Three scopes are supported via the scope query parameter (route.ts:46-50):
ScopeTables affected
interactionsinteraction_history, interaction_summary
tracesdecision_traces
allinteractions + traces + experiment_assignments + impressions (DSAR-style full purge)
Default scope is all (route.ts:44).

Path Parameters

ParameterTypeDescription
customerIdstringCustomer identifier to purge.

Query Parameters

scope
string
default:"all"
One of interactions, traces, all. Any other value returns 400.

Required headers

HeaderRequiredRead atPurpose
X-Confirm-DeleteYesroute.ts:36Must equal the customerId path parameter. Mismatch returns 400.
X-API-KeyYes (one of the two)tenant.ts:97API key (krn_…)
X-Tenant-IdYes (one of the two)tenant.ts:113Direct tenant id

Response

Returned at route.ts:112-118.
{
  "success": true,
  "customerId": "cust_42",
  "scope": "all",
  "totalDeleted": 232,
  "deleted": {
    "interactionHistory": 142,
    "interactionSummary": 23,
    "decisionTraces": 0,
    "experimentAssignments": 0,
    "impressions": 67
  }
}
totalDeleted
number
Sum of all per-table counts.
deleted
object
Per-table delete counts. Tables outside the requested scope are absent. decisionTraces, experimentAssignments, and impressions are wrapped in try/catch — if the table is unavailable the count is reported as 0 rather than failing the request (route.ts:74-97).

Status codes

CodeWhenSource
200Deletion succeededroute.ts:112
400Missing or mismatched X-Confirm-Delete headerroute.ts:37-41
400Invalid scope query valueroute.ts:46-50
401Caller is not authenticatedrequireRole
403Caller is not adminrequireRole(request, "admin") at route.ts:29
500Unexpected errorroute.ts:120

Audit

Every successful call writes one delete row to audit_logs with entityType: "customer_data" and the per-table counts in changes (route.ts:101-108). The audit row is fire-and-forget — a failed log write does not roll back the deletion.

Roles

admin only.
Permanent deletion. The operation cannot be undone. Use this endpoint when fulfilling a DSAR/right-to-erasure request — for soft suppression of a single customer in active campaigns, use the Suppressions API instead.


Role requirements

EndpointAllowed Roles
GET /customers/{id}/eligibilityadmin, editor, viewer
GET /customers/{id}/profileadmin, editor, viewer
POST /customers/{id}/simulateadmin, editor, viewer
GET /customers/{id}/suppressionsadmin, editor, viewer
GET /customers/{id}/summariesadmin, editor, viewer
DELETE /customers/{id}admin
DELETE /customers/{id}/dataadmin