Skip to main content

Quickstart: your first API call

Everything the Kumkuat app does is available over the REST API. This guide takes you from a workspace to your first authenticated call: you will create a key, check which workspace it belongs to, and list the audiences you can put content in front of.

Before you start​

You need a Kumkuat workspace with at least one audience persona in it. If the workspace is new, install a few audiences from the Marketplace or create your own first.

The base URL for every call is:

https://api.kumkuat.ai

1. Create an API key​

Keys are created in the app under Settings. There are two kinds, and both are sent the same way:

KindWhereActs as
Personal API keySettings → Personal → Security & API keysYou, with your role in the workspace. Scorecards it generates show in the app only to you.
Workspace API keySettings → Workspace → API & integrations → Workspace API keys (admin or owner only)The workspace itself. Scorecards it generates show to every member.

The raw key is shown once, when it is created. Store it in a secret store on your server and never ship it to a browser or a mobile app. Revoking a key cuts off anything using it immediately.

Every key is bound to one workspace. If you integrate several brands or customers, you hold one key per workspace.

Which kind should an integration use?

Use a workspace key for scoring: it keeps working when a member leaves, and the scorecards it produces are shared with the whole team in the app. Two calls in these guides currently require a personal key from an admin or owner account: listing personas (GET /api/v1/personas) and creating documents (POST /api/v1/documents). If your integration makes those calls, hold both kinds. Every other call in these guides accepts either.

2. Authenticate​

Send the key in the X-API-Key header on every request. Authorization: Bearer with the same key is accepted too.

curl https://api.kumkuat.ai/api/v1/workspace \
-H "X-API-Key: $KUMKUAT_API_KEY"
{
"workspace_id": "ws_9738dfeb738a44debb10",
"name": "Entertainment",
"company": "Netflix, Inc.",
"role": "owner",
"is_owner": true,
"is_active": true,
"website": "",
"description": "",
"settings": { "company": "Netflix, Inc.", "…": "…" },
"created_at": "2026-02-13T16:12:22.987726+00:00",
"updated_at": "2026-09-03T16:21:08.541942+00:00"
}

role is the role the key acts with. A personal key carries its owner's role; a workspace key reports member. Show name and company in your own UI so people can see which workspace an integration is connected to.

3. List the audience categories​

Personas are filed under categories such as Journalists, Consumer or Investors & Capital Markets. The category list carries the workspace's own display order, so use it to group your audience picker.

curl https://api.kumkuat.ai/api/v1/audience-groups \
-H "X-API-Key: $KUMKUAT_API_KEY"
{
"groups": [
{ "id": "59a69729-01e7-42b3-a6a8-bbb6f28e9c55", "name": "Regulators & Legislators", "display_name": null, "sort_order": 0 },
{ "id": "83cfea06-3058-4daa-b5c7-bd3f568841eb", "name": "Journalists", "display_name": null, "sort_order": 1 },
{ "id": "733a2522-087f-431c-9abc-3945349fd1ba", "name": "Consumer", "display_name": null, "sort_order": 2 },
"…"
]
}

display_name is the label to show when it is set; fall back to name. Personas reference the category by name.

4. List the personas​

GET /api/v1/personas?summary=1 returns every persona in the workspace as a compact object of about twenty fields. Add category=Consumer to filter to one category.

curl "https://api.kumkuat.ai/api/v1/personas?summary=1&category=Consumer" \
-H "X-API-Key: $KUMKUAT_API_KEY"

One entry from the response:

{
"personas": [
{
"id": "8e049a2e-92dd-4077-b6ca-e7154edc7de4",
"name": "Price-Sensitive Subscriber",
"description": "An individual or household primarily driven by cost-effectiveness when making purchasing decisions …",
"category": "Consumer",
"entity_kind": "archetype",
"entity_kind_label": "Segment",
"tone": "friendly",
"communication_style": "Clear, direct, and transparent about pricing and terms …",
"avatar_url": "",
"include_in_audience": true,
"include_in_voice_list": false,
"has_template": true,
"is_active": true,
"is_marketplace_managed": false,
"labels": [],
"created_at": "2026-02-13T16:50:34.332525+00:00",
"updated_at": "2026-07-25T21:09:41.398382+00:00"
},
"…"
],
"total": 74
}

The fields an audience picker needs:

FieldUse it for
idThe value you send when scoring content. Stable for the life of the workspace.
name, description, avatar_urlDisplay. avatar_url may be empty.
categoryGrouping, matched to name in the category list above.
entity_kind_labelIndividual, Organization or Segment: whether the persona stands for a named individual, an outlet or institution, or an audience segment.
include_in_audiencefalse marks a persona kept only as a writing voice. Leave those out of an audience picker.
has_templatefalse means the persona has no profile to react from yet. Leave those out too.

The full persona object, with its profile, linked sources and voice profiles, is available per persona at GET /api/v1/personas/{persona_id}. Without summary=1 the list returns full objects and paginates with limit (default 200, maximum 500) and offset; total tells you whether there are more.

Errors​

Every error is JSON with an error message. The status code tells you what kind:

StatusBodyMeaning
401{"error": "API key or bearer token required"} or {"error": "Invalid API key"}No key, a revoked key, or a typo
403{"code": "permission_denied", "error": "…", "permission": "persona.read"}The key's role lacks a permission an admin has withheld in Settings → Members & roles
403{"error": "Admin or owner access required"}The call needs an admin or owner key
403{"error": "Workspace is not active"}The workspace has been deactivated
400{"error": "personas must be a non-empty array"}A required field is missing or malformed
404{"error": "Persona not found"}The id is unknown, or belongs to another workspace
422A list of {"loc", "msg", "type"} entriesA typed request body failed validation
5xx{"error": "…"}Retry with backoff

Conventions​

  • JSON in, JSON out. Send Content-Type: application/json on requests with a body.
  • Identifiers are opaque strings and stay stable for the life of a workspace. Timestamps are ISO 8601 in UTC.
  • Work that calls a model can take from seconds to a minute. Set client timeouts of at least two minutes on those calls, or use the background-job variant where one exists and poll GET /api/v1/jobs/{job_id}.
  • Lists paginate. Documents use page and per_page and return a pagination object; personas use limit and offset and return total.
  • Model-backed calls draw on the workspace's run budget. Identical requests are served from cache and cost nothing.

Next steps​