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

# SDK Quickstart

> Integrate with the KaireonAI Recommend and Respond APIs from JavaScript or Python in minutes.

## Overview

This guide shows you how to call the KaireonAI APIs from **JavaScript (Node.js / browser)** and **Python**. Both examples cover the two core endpoints:

* **Recommend** -- get personalized next-best-action offers for a customer
* **Respond** -- record outcomes (impressions, clicks, conversions) to close the feedback loop

## Prerequisites

| Requirement | Where to find it                                                                        |
| ----------- | --------------------------------------------------------------------------------------- |
| Base URL    | `https://your-instance.kaireonai.com` or `https://playground.kaireonai.com` for testing |
| Tenant ID   | **Settings > General** in the KaireonAI UI                                              |
| API Key     | **Settings > API Explorer** -- create one and copy the raw key                          |

Every request sends your two auth headers plus a JSON content type:

```
X-Tenant-Id: <your-tenant-id>
X-API-Key: <your-api-key>
Content-Type: application/json
```

<Info>
  For API-key requests, `Content-Type: application/json` is what satisfies the
  server's CSRF check — the `X-Requested-With` header is only needed for
  browser/cookie-authenticated (same-origin) calls.
</Info>

***

## JavaScript

### Install dependencies

No SDK package is needed -- the built-in `fetch` API works in Node 18+ and all modern browsers. If you prefer a library:

```bash theme={null}
npm install node-fetch   # only needed for Node < 18
```

### Recommend API

```javascript theme={null}
const BASE_URL = "https://playground.kaireonai.com";

const headers = {
  "Content-Type": "application/json",
  "X-Tenant-Id": "YOUR_TENANT_ID",
  "X-API-Key": "YOUR_API_KEY",
  "X-Requested-With": "XMLHttpRequest",
};

async function getRecommendations(customerId, limit = 3) {
  const response = await fetch(`${BASE_URL}/api/v1/recommend`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      customerId,
      limit,
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Recommend failed (${response.status}): ${error.error}`);
  }

  return response.json();
}

// Usage
const result = await getRecommendations("SBX-000100");
console.log("Decisions:", result.decisions);
console.log("Recommendation ID:", result.recommendationId);
```

**Response shape:**

```json theme={null}
{
  "recommendationId": "rec-uuid",
  "customerId": "SBX-000100",
  "count": 3,
  "decisions": [
    {
      "offerId": "offer-abc",
      "offerName": "Retail Rewards: Discount — 10 Day Low",
      "categoryName": "Retail Rewards: Retention",
      "channelName": "Retail Rewards: Email",
      "creativeId": "creative-xyz",
      "score": 0.85,
      "rank": 1,
      "content": { "subject": "Special offer", "body": "<p>Save today</p>" },
      "personalization": {}
    }
  ],
  "meta": { "totalCandidates": 60, "afterQualification": 60, "afterContactPolicy": 60, "degradedScoring": false }
}
```

### Respond API

After the customer sees or interacts with an offer, record the outcome:

```javascript theme={null}
async function recordOutcome(customerId, creativeId, outcome) {
  const response = await fetch(`${BASE_URL}/api/v1/respond`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      customerId,
      creativeId,  // from the recommend response decisions[].creativeId
      outcome,     // e.g. "impression", "click", "dismiss", "conversion"
      idempotencyKey: `${outcome}-${Date.now()}`,
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Respond failed (${response.status}): ${error.error}`);
  }

  return response.json();
}

// Usage — record a click on the first decision
const decision = result.decisions[0];
await recordOutcome("SBX-000100", decision.creativeId, "click");
```

**Response shape (201 Created):**

```json theme={null}
{
  "interactionId": "interaction-uuid",
  "customerId": "SBX-000100",
  "outcome": "click",
  "classification": "positive",
  "offerName": "Retail Rewards: Discount — 10 Day Low",
  "status": "recorded"
}
```

### Error handling

Wrap calls in a try/catch and handle common status codes:

```javascript theme={null}
try {
  const recs = await getRecommendations("cust-001");
} catch (err) {
  // 401 -- invalid API key or tenant ID
  // 404 -- customer not found or no active decision flow
  // 422 -- validation error (bad request body)
  // 429 -- rate limited
  // 500 -- server error
  console.error("API error:", err.message);
}
```

***

## Python

### Install dependencies

```bash theme={null}
pip install requests
```

### Recommend API

```python theme={null}
import requests

BASE_URL = "https://playground.kaireonai.com"

HEADERS = {
    "Content-Type": "application/json",
    "X-Tenant-Id": "YOUR_TENANT_ID",
    "X-API-Key": "YOUR_API_KEY",
    "X-Requested-With": "XMLHttpRequest",
}


def get_recommendations(customer_id: str, limit: int = 3) -> dict:
    response = requests.post(
        f"{BASE_URL}/api/v1/recommend",
        headers=HEADERS,
        json={
            "customerId": customer_id,
            "limit": limit,
        },
    )
    response.raise_for_status()
    return response.json()


# Usage
result = get_recommendations("SBX-000100")
print("Decisions:", result["decisions"])
print("Recommendation ID:", result["recommendationId"])
```

### Respond API

```python theme={null}
import time

def record_outcome(
    customer_id: str,
    creative_id: str,
    outcome: str,
) -> dict:
    response = requests.post(
        f"{BASE_URL}/api/v1/respond",
        headers=HEADERS,
        json={
            "customerId": customer_id,
            "creativeId": creative_id,   # from decisions[].creativeId
            "outcome": outcome,          # e.g. impression, click, dismiss, conversion
            "idempotencyKey": f"{outcome}-{int(time.time())}",
        },
    )
    response.raise_for_status()
    return response.json()


# Usage — record a click on the first decision
decision = result["decisions"][0]
record_outcome("SBX-000100", decision["creativeId"], "click")
```

### Error handling

```python theme={null}
from requests.exceptions import HTTPError

try:
    recs = get_recommendations("cust-001")
except HTTPError as err:
    status = err.response.status_code
    body = err.response.json()
    # 401 -- invalid API key or tenant ID
    # 404 -- customer not found or no active decision flow
    # 422 -- validation error (bad request body)
    # 429 -- rate limited
    # 500 -- server error
    print(f"API error ({status}): {body.get('error', 'Unknown')}")
```

***

## Next steps

* **[API Tutorial](/tutorials/api-tutorial)** -- deep dive into request/response formats, decision traces, and experiments
* **[Computed Values](/tutorials/computed-values)** -- personalize offers with dynamic formulas
* **[Sample Data](/get-started/sample-data)** -- load sample offers and customers into your instance
