AI and automations API

Read AI-generated summaries of conversations, customers and custom objects, list your AI agents, and test them with evaluations, test cases and runs. Includes a CI script that fails a build when an agent's score drops.

The AI API covers three things:

AreaEndpointsUse it to
Summaries/v1/ai/summariesRead the AI summary of a conversation, customer or custom object, optionally translated
Automations/v1/ai/automationsList your AI agents and look one up. Read-only: agents are built in Kustomer.
Evaluations/v1/ai/evaluations, /v1/ai/evaluation-testcases, /v1/ai/evaluation-runs, /v1/ai/evaluation-testcase-resultsTest an AI agent against a suite of scenarios and score it, from a script or CI

All endpoints use the same authentication and JSON:API format as the rest of the API, under https://<org>.api.kustomerapp.com. Every operation is in the API reference.

Summaries

Kustomer generates summaries automatically and updates them as a conversation, customer or custom object changes. The API reads them; it doesn't create them.

get/v1/ai/summaries/{resourceId}
cURL
curl "https://acme.api.kustomerapp.com/v1/ai/summaries/6716a3a9c4e5f60012ab34c1?lang=fr" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY"
Response
{
  "data": {
    "type": "summary",
    "id": "6716a4f0c4e5f60012ab34f2",
    "attributes": {
      "resourceId": "6716a3a9c4e5f60012ab34c1",
      "resourceType": "conversation",
      "text": "Le client a demandé où en était sa commande 4417 et a demandé un remboursement…",
      "createdAt": "2026-10-14T15:02:11.000Z",
      "updatedAt": "2026-10-14T15:20:43.000Z",
      "lastSummarizedAt": "2026-10-14T15:20:43.000Z"
    }
  }
}
  • resourceType is conversation, customer or kobject.
  • lang translates the text (for example fr, es, de). If translation fails, you get the summary in its original language.
  • lastSummarizedAt tells you how fresh the summary is.

To fetch many at once, pass up to 100 IDs:

get/v1/ai/summaries/batch
cURL
curl -G "https://acme.api.kustomerapp.com/v1/ai/summaries/batch" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  --data-urlencode "resourceIds=6716a3a9c4e5f60012ab34c1,6716a3b2c4e5f60012ab34c7"

The response's data is an array. Resources without a summary are left out rather than returned as errors, so match results on attributes.resourceId. IDs must be 24-character hex strings. page, pageSize and lang work as above.

Automations

Automations are the AI agents you build in Kustomer. The API lists them so you can find the ID to evaluate; creating and editing agents happens in Kustomer.

get/v1/ai/automations
Query parameterMeaning
typecustomer (default), rep, conversational or workflow
nameFilter by name
triggersComma-separated trigger event names
page, pageSizePagination

Each automation has name, description, type, machineUserId (the user the agent acts as), version, and timestamps. The API returns version 0, the agent's current draft, which is also what evaluations test. Get one with GET /v1/ai/automations/{automationId}.

Evaluations

An evaluation is a test suite for one AI agent. You write test cases (a customer message plus what a good answer looks like), run them, and get a score.

Automation
(AI agent)

Evaluation
a named suite

Test case
input · expectedOutput · toolCalls

Test case

Run
status · score · scoreByTestCase

Result
output · assertionResult · traceId

Result

Diagram source
flowchart LR
  A["Automation<br/>(AI agent)"] --> E["Evaluation<br/>a named suite"]
  E --> T1["Test case<br/>input · expectedOutput · toolCalls"]
  E --> T2["Test case"]
  E --> R["Run<br/>status · score · scoreByTestCase"]
  R --> X1["Result<br/>output · assertionResult · traceId"]
  R --> X2["Result"]
InteractiveAn evaluation run
POST /v1/ai/evaluations/…/run { "runsPerTestCase": 3 }status pendingscore —
  • Refund within policy
    expects tool IssueRefund
    —
  • Refund outside policy
    rubric only
    —
  • Order status
    expects tool LookupOrder
    —
  • Angry customer
    rubric only
    —
Refund within policy · run 1
input I'd like a refund for order 4417, it arrived broken.
expectedOutput Apologizes, confirms the 30-day window, offers a full refund
status: pending…
runsPerTestCase is 3, so each test case runs three times. Select a result to see the agent's answer and the judge's reasoning.

How scoring works

Each run executes every test case runsPerTestCase times against the agent. An LLM judge scores each result pass or fail:

A result fails whenShown in
The agent erroredstatus: "error" and error
The answer doesn't meet expectedOutputassertionResult.inputResult.met: false, with the judge's explanation and confidence
An expected tool wasn't calledassertionResult.toolCallsResult[].toolCalled: false

A test case's score is the percentage of its results that passed (scoreByTestCase), and the run's score is the overall percentage, from 0 to 100. A test case with neither expectedOutput nor toolCalls always passes, so give every case at least one.

During a run, tools with side effects (sending messages, changing data, non-GET HTTP calls) aren't executed, but the call is still recorded, so you can assert that the agent would have called IssueRefund without issuing one.

1. Create an evaluation

post/v1/ai/evaluations
cURL
curl -X POST "https://acme.api.kustomerapp.com/v1/ai/evaluations" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "automationId": "6716c0a1c4e5f60012ab36d0", "name": "Refunds" }'

List an agent's evaluations with GET /v1/ai/automations/{automationId}/evaluations.

2. Add test cases

post/v1/ai/evaluation-testcases
Request body
{
  "evaluationId": "6716c1d2c4e5f60012ab36ea",
  "name": "Refund within policy",
  "input": "I'd like a refund for order 4417, it arrived broken.",
  "resourceType": "customer",
  "resourceId": "6716a3a9c4e5f60012ab34c1",
  "expectedOutput": "Apologizes, confirms the order is within the 30-day window, and offers a full refund.",
  "toolCalls": [{ "id": "6716c2e3c4e5f60012ab3701", "name": "IssueRefund" }]
}
Test case
evaluationIdstringrequired
namestringrequired
inputstringrequired
resourceTypestringrequired
resourceIdstringrequired
expectedOutputstring
toolCallsarray
conversationIdstring
messageIdstring
resumeNodestring

Turn real conversations into regression tests: when an agent mishandles a chat, create a test case with that conversation's conversationId, the customer's messageId, and an expectedOutput describing the right answer.

Update a test case with PUT /v1/ai/evaluation-testcases/{testCaseId}. Send input, resourceId and resourceType each time. Leaving out toolCalls keeps the existing ones, and [] clears them. The conversation fields can't be changed after creation.

3. Run it

post/v1/ai/evaluations/{evaluationId}/run
cURL
curl -X POST "https://acme.api.kustomerapp.com/v1/ai/evaluations/6716c1d2c4e5f60012ab36ea/run" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "runsPerTestCase": 3 }'

The response is a run with status: "pending". It moves to running and then completed.

StatusMeaning
404The evaluation doesn't exist or has no test cases
409A run of this evaluation is already in progress

Running the same case several times exposes flaky behavior. Each run uses AI capacity in proportion to test cases × runsPerTestCase, so size it deliberately.

4. Read the results

Poll the run until it completes:

get/v1/ai/evaluation-runs/{runId}
Completed run
{
  "data": {
    "type": "evaluation-run",
    "id": "6716c3f4c4e5f60012ab3712",
    "attributes": {
      "evaluationId": "6716c1d2c4e5f60012ab36ea",
      "status": "completed",
      "score": 83.3,
      "scoreByTestCase": { "6716c2a0c4e5f60012ab36f5": 100, "6716c2b1c4e5f60012ab36f9": 66.7 },
      "runsPerTestCase": 3,
      "durationInNanos": 41200000000
    }
  }
}

Then list the individual results to see what failed and why:

get/v1/ai/evaluation-testcase-results
Failed results with the judge's reasoning
curl -sG "https://acme.api.kustomerapp.com/v1/ai/evaluation-testcase-results" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  --data-urlencode "evaluationRunIds=6716c3f4c4e5f60012ab3712" \
  --data-urlencode "pageSize=100" \
| jq -r '.data[].attributes
    | select(.status == "error" or .assertionResult.assertionFailed)
    | [.testCaseId, .status, (.assertionResult.inputResult.explanation // .error)] | @tsv'

Each result has the agent's output, the tools it called (toolCalls[].canonicalName, toolInput, toolOutput), assertionResult, timing, and a traceId for following the run step by step in Kustomer.

Gate deploys on agent quality

Because runs test the agent's draft, you can check a change before turning it on. This script runs an evaluation, waits for it, and exits non-zero if the score is below a threshold, ready for a CI job:

eval-gate.ts
const BASE = `https://${process.env.KUSTOMER_ORG}.api.kustomerapp.com`
const EVALUATION_ID = process.env.EVALUATION_ID!
const MIN_SCORE = Number(process.env.MIN_SCORE ?? 85)

async function api<T>(method: string, path: string, body?: unknown): Promise<T> {
  const res = await fetch(BASE + path, {
    method,
    headers: { Authorization: `Bearer ${process.env.KUSTOMER_API_KEY}`, 'Content-Type': 'application/json' },
    body: body ? JSON.stringify(body) : undefined,
  })
  if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${await res.text()}`)
  return res.json() as Promise<T>
}

type Run = { data: { id: string; attributes: { status: 'pending' | 'running' | 'completed'; score?: number } } }

const started = await api<Run>('POST', `/v1/ai/evaluations/${EVALUATION_ID}/run`, { runsPerTestCase: 3 })
let run = started
while (run.data.attributes.status !== 'completed') {
  await new Promise((r) => setTimeout(r, 10_000))
  run = await api<Run>('GET', `/v1/ai/evaluation-runs/${started.data.id}`)
}

const score = run.data.attributes.score ?? 0
console.log(`Evaluation score: ${score} (minimum ${MIN_SCORE})`)
if (score < MIN_SCORE) process.exit(1)

With kusty, the same steps are kusty evaluations runevaluation --evaluationId … --data '{"runsPerTestCase":3}' and kusty evaluation-runs get --runId …, or ask your AI assistant through the kusty MCP server to run the evals and explain the failures.

Endpoint summary