Overview
This tutorial covers everything you need to integrate with Kaireon’s two core APIs:
- Recommend API — Get personalized offer recommendations for a customer
- Respond API — Record customer interactions (impressions, clicks, conversions)
Prerequisites
Before starting, ensure you have:
- A running Kaireon instance (local or
https://playground.kaireonai.com)
- At least one active decision flow with offers, channels, and creatives configured
- Your tenant ID (found in Settings > General)
- An API key (generated in Settings > API Keys)
Authentication
All API requests require two headers:
| Header | Description |
|---|
x-tenant-id | Your tenant identifier |
x-api-key | Your API key (hashed with HMAC-SHA256 on the server) |
curl -H "x-tenant-id: your-tenant-id" \
-H "x-api-key: your-api-key" \
https://your-instance.com/api/v1/recommend
API keys are hashed on the server using HMAC-SHA256 with the API_KEY_PEPPER environment variable. Store your API key securely — it cannot be retrieved after creation.
Base URL
| Environment | Base URL |
|---|
| Local development | http://localhost:3000/api/v1 |
| Playground | https://playground.kaireonai.com/api/v1 |
| Production | Your custom domain + /api/v1 |
Recommend API
The Recommend API is the primary decisioning endpoint. It executes a decision flow for a specific customer and returns ranked, personalized offers.
Endpoint
Request Body
{
"customerId": "cust_12345",
"channelId": "ch_email",
"decisionFlowId": "df_credit_cards",
"maxOffers": 3,
"placement": "hero_offer",
"attributes": {
"tier": "gold",
"source": "campaign_q1",
"device": "mobile"
},
"trace": true
}
| Field | Type | Required | Description |
|---|
customerId | string | Yes | The customer to generate recommendations for |
channelId | string | Yes | Delivery channel (determines which creatives are selected) |
decisionFlowId | string | No | Specific flow to execute (uses default flow if omitted) |
maxOffers | number | No | Maximum offers to return (default: 5) |
placement | string | No | Named placement slot within the channel |
attributes | object | No | Request-time attributes available as attributes.* in formulas |
trace | boolean | No | If true, returns a decision trace ID for debugging |
Response
{
"customerId": "cust_12345",
"recommendations": [
{
"offerId": "act_platinum_cc",
"offerName": "Platinum Rewards Card",
"categoryId": "cat_credit_cards",
"rank": 1,
"score": 0.89,
"channelId": "ch_email",
"creativeId": "treat_platinum_email",
"content": {
"subject": "You're invited, Sarah - Earn 3x Rewards",
"headline": "Platinum Rewards Card",
"body": "Start earning 3x points with a personalized rate of 17.49% APR.",
"ctaText": "Apply Now",
"ctaUrl": "https://example.com/apply/platinum"
},
"personalization": {
"personalized_rate": 17.49,
"annual_fee_waiver": true
}
},
{
"offerId": "act_cashback",
"offerName": "Cash Back Card",
"rank": 2,
"score": 0.74,
"channelId": "ch_email",
"creativeId": "treat_cashback_email",
"content": {
"subject": "Sarah, get 2% cash back on everything",
"headline": "Cash Back Card",
"body": "No annual fee, 2% cash back on all purchases.",
"ctaText": "Learn More",
"ctaUrl": "https://example.com/apply/cashback"
},
"personalization": {
"personalized_rate": 18.24
}
}
],
"decisionFlowId": "df_credit_cards",
"traceId": "trace_abc123",
"processedAt": "2026-03-10T14:30:00Z"
}
Response Fields
| Field | Description |
|---|
recommendations[] | Ordered array of recommended offers (highest score first) |
recommendations[].score | Final composite score after arbitration |
recommendations[].content | Rendered creative content with personalization variables resolved |
recommendations[].personalization | Computed values from the Compute stage |
traceId | Decision trace ID (only when trace: true in request) |
Respond API
The Respond API records customer interactions with recommendations. This data feeds back into behavioral metrics, contact policies, and experiment analysis.
Endpoint
Request Body
{
"customerId": "cust_12345",
"offerId": "act_platinum_cc",
"channelId": "ch_email",
"outcomeType": "click",
"creativeId": "treat_platinum_email",
"traceId": "trace_abc123",
"metadata": {
"clickPosition": "hero_banner",
"deviceType": "mobile"
}
}
| Field | Type | Required | Description |
|---|
customerId | string | Yes | The customer who interacted |
offerId | string | Yes | The offer they interacted with |
channelId | string | Yes | The channel the interaction occurred on |
outcomeType | string | Yes | The type of interaction (see Outcome Types) |
creativeId | string | No | The specific creative/treatment shown |
traceId | string | No | Links this interaction back to the original recommendation |
metadata | object | No | Arbitrary key-value data attached to the interaction |
Response
{
"id": "int_xyz789",
"customerId": "cust_12345",
"offerId": "act_platinum_cc",
"channelId": "ch_email",
"outcomeType": "click",
"creativeId": "treat_platinum_email",
"traceId": "trace_abc123",
"recordedAt": "2026-03-10T15:45:00Z"
}
Common Outcome Types
| Type | When to Record |
|---|
impression | Customer was shown the recommendation |
click | Customer clicked/tapped the recommendation |
conversion | Customer completed the desired action (purchase, application, etc.) |
dismiss | Customer explicitly dismissed the recommendation |
not_interested | Customer indicated disinterest |
opt_out | Customer opted out of this type of communication |
Advanced Topics
Decision Traces
When you set trace: true in the Recommend request, Kaireon records a forensic trace of the entire decision process. Retrieve it with:
GET /api/v1/decision-traces/:traceId
Trace response:
{
"traceId": "trace_abc123",
"customerId": "cust_12345",
"decisionFlowId": "df_credit_cards",
"stages": [
{
"name": "enrich",
"duration": 12,
"input": { "customerId": "cust_12345" },
"output": { "customer.loyalty_score": 85, "customer.credit_score": 720 }
},
{
"name": "compute",
"duration": 3,
"computed": {
"act_platinum_cc": { "personalized_rate": 17.49 },
"act_cashback": { "personalized_rate": 18.24 }
}
},
{
"name": "filter",
"duration": 5,
"candidatesIn": 15,
"candidatesOut": 8,
"filtered": ["act_home_loan (segment_required)", "act_auto_loan (propensity < 0.4)"]
},
{
"name": "score",
"duration": 8,
"scores": {
"act_platinum_cc": 0.89,
"act_cashback": 0.74
}
},
{
"name": "rank",
"duration": 2,
"finalOrder": ["act_platinum_cc", "act_cashback"]
}
],
"totalDuration": 30,
"processedAt": "2026-03-10T14:30:00Z"
}
Decision traces are invaluable for debugging why a specific offer was or was not recommended. Enable tracing in staging environments and at a sample rate in production (configurable in Settings > Tracing).
Experiments
When an A/B experiment is active, the Recommend API automatically assigns customers to control or variant groups based on creative weights. The response includes experiment metadata:
{
"recommendations": [
{
"offerId": "act_platinum_cc",
"creativeId": "treat_platinum_email_variant_a",
"experiment": {
"experimentId": "exp_cc_cta_test",
"variant": "variant_a",
"weight": 30
}
}
]
}
Track experiment results in Algorithms > Experiments, where Kaireon calculates:
- Conversion rate per variant
- Uplift (percentage improvement over control)
- Statistical significance (z-test)
- Confidence interval
Computed Values in Responses
The personalization field in each recommendation contains the evaluated computed values from the decision flow’s Compute stage. These values are calculated per customer using:
- Offer custom fields —
base_rate, annual_fee, etc.
- Enriched customer data —
customer.loyalty_score, customer.credit_score
- Request-time attributes —
attributes.tier, attributes.device
{
"personalization": {
"personalized_rate": 17.49,
"annual_fee_waiver": true,
"bonus_points": 5000
}
}
See Computed Values for formula syntax and configuration details.
Error Handling
Common Error Responses
| Status | Code | Description |
|---|
| 400 | VALIDATION_ERROR | Invalid request body (missing required fields, wrong types) |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | Tenant does not have access to the requested resource |
| 404 | NOT_FOUND | Decision flow, customer, or offer not found |
| 429 | QUOTA_EXCEEDED | Monthly decision quota reached (see Licensing) |
| 500 | INTERNAL_ERROR | Server error — contact support |
Error response format:
{
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": [
{ "field": "customerId", "message": "customerId is required" }
]
}
Rate Limiting
Kaireon applies a sliding-window rate limit to protect the platform:
| Tier | Rate Limit |
|---|
| Community | 100 requests/minute |
| Professional | 1,000 requests/minute |
| Enterprise | Custom (configurable) |
When rate-limited, the API returns:
HTTP 429 Too Many Requests
Retry-After: 12
Rate limits apply per tenant, not per API key. Multiple API keys for the same tenant share the same rate limit window.
What’s Next?