Quickstart

Quickstart

From an API key to a model explained and analysed, in five steps and about ten minutes.

The steps use a built-in reference model, so there is nothing to deploy. Swap in your own model with one upload call or a scoring endpoint when you are ready.

Create an API key

Sign up on the free plan, then open API keys in the dashboard and create a key. Keys look like km_live_… and are shown once. A key authenticates every /v1 endpoint except account management, which needs a dashboard session (see Authentication).

Install the client

Python 3.9 or newer. The models extra adds NumPy, which uploading a fitted estimator needs; images adds Pillow for photo helpers.

shell
pip install kaimei
pip install "kaimei[models]"      # upload fitted estimators (NumPy)
pip install "kaimei[images]"      # load and render photos (Pillow)
pip install matplotlib            # optional: charts in the dashboard's colours

export KAIMEI_API_KEY=km_live_...   # read automatically by Kaimei()

Register a model

A model is a feature schema plus a way to run it. The quickest start is a reference model that ships with Kaimei: register it under a slug of your own and it behaves like a model you deployed, complete with reference data for the explanations to compare against.

from kaimei import Kaimei

client = Kaimei()  # KAIMEI_API_KEY from the environment

model = client.models.create(
    name="Credit risk v3",
    slug="credit-risk-v3",
    inference={"type": "builtin", "name": "credit-risk"},
)
print(model.id, model.task, [f["name"] for f in model.features])
# mdl_390bd6d9568f626851ef binary_classification ['income', 'credit_score', ...]
curl https://api.kaimei.ai/v1/models \
  -H "Authorization: Bearer $KAIMEI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Credit risk v3", "slug": "credit-risk-v3",
       "inference": {"type": "builtin", "name": "credit-risk"}}'

Explain a prediction

Pass any input row. Kaimei runs the model, computes attributions for the explained class, ranks them in top_features and, if you ask, searches for the smallest change that would flip the decision. Features you leave out take their baseline from the schema.

explanation = client.explanations.create(
    model="credit-risk-v3",
    input={"income": 72000, "credit_score": 681, "utilization": 0.41,
           "debt_to_income": 0.38, "loan_amount": 18000, "employment_years": 4,
           "num_delinquencies": 1, "age": 34, "home_ownership": "rent"},
    method="shap",
    options={"counterfactual": True, "frozen_features": ["age"]},
)

print(explanation.output["label"], round(explanation.output["value"], 3))
# decline 0.595
print(explanation.counterfactual["changes"])
# [{'feature': 'credit_score', 'from': 681, 'to': 850, 'output_after': 0.083, 'label_after': 'approve'}]
explanation            # in a notebook: the Kaimei card, bars and all
explanation.to_frame() # or the same numbers as a pandas DataFrame
curl https://api.kaimei.ai/v1/explanations \
  -H "Authorization: Bearer $KAIMEI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "credit-risk-v3",
    "input": {"income": 72000, "credit_score": 681, "utilization": 0.41,
              "debt_to_income": 0.38, "loan_amount": 18000, "employment_years": 4,
              "num_delinquencies": 1, "age": 34, "home_ownership": "rent"},
    "method": "shap",
    "options": {"counterfactual": true, "frozen_features": ["age"]}
  }'
201 CreatedResponse
{
  "object": "explanation",
  "id": "exp_7d7add16c796eafac087",
  "model_id": "mdl_390bd6d9568f626851ef",
  "prediction_id": "pred_2b3edef200ac9fba4e3c",
  "method": "shap",
  "output": {
    "label": "decline",
    "class_index": 1,
    "probability": 0.5947,
    "probabilities": {"approve": 0.4053, "decline": 0.5947},
    "target_label": "decline",
    "target_index": 1,
    "value": 0.5947,
    "name": "decision"
  },
  "attributions": {
    "income": -0.052572,
    "credit_score": 0.02092,
    "utilization": -0.062237,
    "debt_to_income": 0.079706,
    "loan_amount": -0.022242,
    "employment_years": 0.007327,
    "num_delinquencies": 0.07484,
    "age": 0.012778,
    "home_ownership": 0.045748
  },
  "base_value": 0.4904,
  "top_features": [
    {
      "feature": "debt_to_income",
      "attribution": 0.079706,
      "value": 0.38,
      "share": 0.2107,
      "direction": "positive",
      "rank": 1
    },
    {
      "feature": "num_delinquencies",
      "attribution": 0.07484,
      "value": 1,
      "share": 0.1978,
      "direction": "positive",
      "rank": 2
    },
    {
      "feature": "utilization",
      "attribution": -0.062237,
      "value": 0.41,
      "share": 0.1645,
      "direction": "negative",
      "rank": 3
    },
    …
  ],
  "counterfactual": {
    "found": true,
    "changes": [
      {
        "feature": "credit_score",
        "from": 681,
        "to": 850,
        "output_after": 0.0834,
        "label_after": "approve"
      }
    ],
    "output_before": 0.5947,
    "output_after": 0.0834,
    "n_evals": 95,
    "target": {"kind": "flip_decision", "threshold": 0.5}
  },
  "n_evals": 32865,
  "latency_ms": 417.8,
  "options": {
    "counterfactual": true,
    "max_changes": 3,
    "frozen_features": ["age"],
    "log_prediction": true,
    "top_k": 8,
    "estimator": "kernel",
    "exact": true,
    "n_coalitions": 510,
    "background_rows": 64,
    "background_source": "reference_data"
  },
  "metadata": {"api_key": "km_live_fPaB"},
  "created_at": "2026-10-31T22:40:23.705348Z"
}

Study the whole model

An analysis runs in the background and writes one insight per step. full runs all seven steps. Poll the analysis, or let the client wait, then read the insights.

analysis = client.analyses.create(model="credit-risk-v3", type="full")
analysis = client.analyses.wait(analysis.id)      # polls until completed or failed
print(analysis.status, analysis.n_evals)           # completed 101558

for insight in client.insights.list(model="credit-risk-v3").data:
    print(f"{insight.type:20} {insight.severity:7} {insight.summary}")
# global_importance    info    `credit_score` is the most influential input, followed by ...
# drift                medium  Recent traffic has moderate drift (PSI 0.15). Shifted inputs: ...
curl https://api.kaimei.ai/v1/analyses \
  -H "Authorization: Bearer $KAIMEI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "credit-risk-v3", "type": "full"}'
# {"object": "analysis", "id": "anl_b8d6...", "status": "queued", ...}

curl https://api.kaimei.ai/v1/analyses/anl_b8d673126dcf3cdbe79a \
  -H "Authorization: Bearer $KAIMEI_API_KEY"
# ... "status": "completed", "insight_ids": ["ins_57a8...", ...]

curl "https://api.kaimei.ai/v1/insights?model=credit-risk-v3" \
  -H "Authorization: Bearer $KAIMEI_API_KEY"

Next Everything you just created is in the dashboard: the model, its explanations with attribution bars and counterfactuals, the insight cards, and the architecture view for uploaded models. The Python client's notebook cards link straight to each record.