HomeGuidesAPI Reference
ChangelogHelp CenterCommunityContact Us
API Reference

K-SQL Ask API overview (revision 2026-10-15.pre)

Overview of the K-SQL Ask API introduced in revision 2026-10-15.

OpenAPI Spec

Machine-readable spec for the Reporting API, which includes the K-SQL Ask API (revision 2026-10-15.pre): beta/categories/reporting.json

Before you begin

Check out our general API overview before getting started with specific endpoints.

🚧

The K-SQL Ask API (revision 2026-10-15.pre) is currently in beta.

Send 2026-10-15.pre as your revision header. Endpoint paths and request/response shapes may change before GA. Access is limited to accounts that have been enabled for the API.

📘

Enable the read scopes for the data you want to ask about on your private API key or OAuth token: campaigns:read, catalogs:read, events:read, lists:read, metrics:read, profiles:read, and segments:read. See Required scopes.

The K-SQL Ask API lets you ask a question about your Klaviyo account data in plain language and get a plain-language answer back. K-SQL turns your question into read-only queries over your account's data, runs them, and summarizes the results. The result sets behind the answer are included in the response so you can see how it was reached.

Use cases

Here are some example use cases supported by the K-SQL Ask API:

  • Answer ad hoc questions about your account data without writing queries, for example, "How many orders were placed last week?"
  • Add plain-language data questions to your own internal tools or assistants.
  • Show the figures behind an answer by displaying the returned result sets next to it.

Required scopes

You don't need every scope to call the endpoint. An answer only draws on data that your key's scopes allow, so a key with fewer scopes gets answers based on less of your account's data.

ScopeData it makes available to answers
campaigns:readCampaigns
catalogs:readCatalogs
events:readEvents
lists:readLists
metrics:readMetrics
profiles:readProfiles
segments:readSegments

How it works

  1. You send a question to the Ask Analytics Question endpoint.
  2. K-SQL decides which data it needs and runs read-only queries against it.
  3. You receive an answer, along with the result sets that support it.

If your question is too ambiguous to answer, you receive a clarifying question instead of an answer. Ask again with more detail. Each response has a status that tells you which case you're in:

StatusMeaning
successanswer contains the plain-language answer.
clarificationanswer contains a question for you. result_sets is empty.

Ask Analytics Question

Send a POST request to /api/ksql-ask with your question.

The request supports the following attributes:

AttributeTypeDescription
questionstringRequired. The question to ask, in 1 to 2000 characters.
max_rowsintegerThe maximum number of rows to return in each result set, from 1 to 1000. Defaults to 100.
curl --request POST \
  --url https://a.klaviyo.com/api/ksql-ask \
  --header 'Authorization: Klaviyo-API-Key your-private-api-key' \
  --header 'accept: application/vnd.api+json' \
  --header 'content-type: application/vnd.api+json' \
  --header 'revision: 2026-10-15.pre' \
  --data '
{
  "data": {
    "type": "ksql-ask",
    "attributes": {
      "question": "How many orders were placed last week?",
      "max_rows": 100
    }
  }
}'
{
  "data": {
    "type": "ksql-ask",
    "id": "5b6e9c0a-3f4d-4e57-9a38-2c1f6d7b8e90",
    "attributes": {
      "status": "success",
      "answer": "42 orders were placed last week.",
      "result_sets": [
        {
          "columns": [
            {
              "name": "order_count",
              "type": "long"
            }
          ],
          "rows": [
            [
              42
            ]
          ],
          "row_count": 1,
          "rows_returned": 1,
          "completeness": "complete",
          "description": "Number of orders placed last week.",
          "sql": "SELECT count(*) FROM klaviyo.orders",
          "caveats": []
        }
      ],
      "warnings": []
    }
  }
}

The response id identifies this request.

Clarifying questions

When a question is too ambiguous to answer, the response has status set to clarification and answer holds a question for you. Send a new request with a more specific question. For example, if you send the question "How did my last campaign do?", the response asks which measure you want:

{
  "data": {
    "type": "ksql-ask",
    "id": "0c8d2f61-7a19-4b3e-8e54-6f2a9d1b3c47",
    "attributes": {
      "status": "clarification",
      "answer": "Which measure do you want to see for your last campaign: open rate, click rate, or revenue?",
      "result_sets": [],
      "warnings": []
    }
  }
}

You can then ask again with the detail included, for example, "What was the click rate of my last campaign?"

Understanding the response

Each response has the following attributes:

  • status

    Either success or clarification.

  • answer

    The plain-language answer when status is success, or a clarifying question when status is clarification.

  • result_sets

    The result sets that support the answer. This is always empty when status is clarification, and it can be empty when status is success if the answer didn't require running a query.

  • warnings

    Caveats that change how you should read answer and result_sets, for example, a sampled result set or rows left out by a cap. Show these alongside the answer rather than discarding them.

Each result set has the following attributes:

  • columns

    The result set's columns, each with a name and a type. The type is one of boolean, long, double, string, timestamptz, or unknown.

  • rows

    The result rows. Each row is a list of values in the same order as columns. A value is a boolean for boolean columns, a number for long and double columns, and a string for every other type. A missing value is null.

  • row_count and rows_returned

    row_count is the number of rows in the query's result. rows_returned is the number of rows included in rows, which is lower than row_count when rows were left out by a cap.

  • completeness

    Whether the result set contains everything its query matched. complete means it does. sample means the result may be larger than what the query returned, which is common for list-style questions. truncated means the result reached the maximum result size.

  • description

    A short plain-language description of what the result set contains.

  • sql

    The K-SQL query that produced the result set, so you can see how the figures were derived. It is for explanation only. K-SQL is an internal dialect, and there is no endpoint that runs it. Don't parse it, store it, or build on its syntax.

  • caveats

    Caveats that apply to this result set, in plain language. The same sentences also appear in warnings.

Limits

  • Question length: 1 to 2000 characters.
  • Rows per result set: up to 1000. Use max_rows to request fewer.
  • Rate limits: burst 1/s and steady 15/m.
  • Composer AI Credits: each request uses Composer AI Credits from your account. See Common errors for what happens when an account runs out.
  • Response time: answers can take several seconds, so allow for this in your client's request timeout.

Common errors

The following errors can occur:

  • 400: the question can't be answered as asked. Rephrase it and try again.
  • 403 with code insufficient_ai_credits: the account has no Composer AI Credits left for the current billing period. Increase the account's AI usage limit to continue asking questions. Retrying doesn't help until credits are available.
  • 403 with code forbidden: the account isn't enabled for this API.
  • 503, including codes deadline_exceeded and unverified: a reliable answer couldn't be produced. Retry the request, and honor the Retry-After header when it's present. The Retry-After header indicates the number of seconds to wait before retrying.
  • 500 with code answer_failed: the question couldn't be answered because of a server error.

Example error response

{
  "errors": [
    {
      "id": "7d3f1b52-9c64-4e08-a1d7-5e2b8c4f6a93",
      "status": 403,
      "code": "insufficient_ai_credits",
      "title": "Forbidden.",
      "detail": "This account has no Composer AI Credits left for the current billing period. Increase the account's AI usage limit to continue asking questions.",
      "source": {
        "pointer": "/data"
      },
      "links": {},
      "meta": {
        "available_credits": "0"
      }
    }
  ]
}

Additional resources