Developers

API Documentation

Updated Oct 6, 2026

Reference for the endpoints we openly support for kn_ API-key integrations.

Base URL#

https://api.kindroid.ai/v1

Authentication#

All endpoints require authentication. Send your API key in the Authorization header as a Bearer token:

Authorization: Bearer kn_xxxxxxxxxxxxxxxxxxxxxxxx

Your API key (starts with kn_...) is under Profile → Preferences → API & Integrations: tap Open, then Tap here to reveal API key. You can copy, regenerate or delete the key there. A Kindroid's AI ID is shown as Kin ID at the bottom of its Kin settings menu, and a group chat's group_id is the last part of its web URL (/v2/chat/group/<group_id>).

WARNING: You should only play around with the API if you're a developer interested in tinkering with integrating Kindroid. DO NOT share your key with anyone who asks, and unless it comes from admins do not trust other sources. Someone with your API key could do anything to your account, including deleting it.

Conventions#

  • Identifiers. ai_id refers to a single Kindroid; group_id refers to a group chat. Endpoints that operate on a conversation take one or the other.
  • Responses. Unless otherwise noted, responses are returned as text/plain. Endpoints that return structured data (e.g. message history) return JSON, as documented per endpoint.
  • Streaming. Endpoints that generate an AI reply accept an optional "stream": true. When set, the response text is streamed as it is generated instead of returned in one blocking response. Omit it (or set false) to receive the full reply once generation completes (except Group AI Response, see below). Streamed text arrives as plain chunks, not data:-framed server-sent events, and may start with whitespace keep-alive bytes during long waits. Because the 200 status is sent before streaming starts, an error that happens mid-stream shows up in the body prefixed with <<HTTP_ERROR>>.
  • Errors. Failures typically return one of: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 429 Too Many Requests (rate limit), 500 Internal Server Error. The response body usually contains a short plain-text description; account restrictions and most Discord bot endpoint errors return a small JSON object instead. If AI generation itself fails, the request still returns 200 and the reply text starts with <<ERROR>>.
  • Rate limits. All requests made with an API key share a limit of 10 requests per 30 seconds per account. Going over it returns 429. Some endpoints have extra limits, noted below.

Endpoints#

Send Message#

Sends a message to an AI and receives a response. This request may take a while, so you should await its response.

Note: Without an active trial or subscription, this endpoint only works while your free preview lasts. Once your account is read-only, requests return 403 Forbidden. See Subscriptions for details.
  • URL: /send-message
  • Method: POST
  • Request Body:
    {
      "ai_id": "string",
      "message": "string",
      "stream": false
    }
    FieldTypeRequiredDescription
    ai_idstringyesThe AI to message.
    messagestringyesThe user's message.
    streambooleannoStream the reply as it is generated.
  • Response:
    • Success: 200 OK with the AI's response as text. With "stream": true, the text is streamed as it is generated.
    • Error: 400, 401, 403, 429, 500

Chat Break#

Ends the current chat and resets the AI's short-term memory. A greeting is mandatory and becomes the first message in the new conversation.

  • URL: /chat-break
  • Method: POST
  • Request Body:
    {
      "ai_id": "string",
      "greeting": "string",
      "wipe_cascaded": false
    }
    FieldTypeRequiredDescription
    ai_idstringyesThe AI to reset.
    greetingstringyesFirst message of the new conversation.
    wipe_cascadedbooleannoAlso wipe the AI's cascaded long-term memory built up from previous conversations. Defaults to false (only short-term memory is reset).
  • Response:
    • Success: 200 OK
    • Error: 400, 401, 403, 429, 500

Get Chat Messages#

Retrieves chat history for a Kindroid or a group chat, oldest first, with cursor pagination.

  • URL: /get-chat-messages
  • Method: GET
  • Query Parameters:
    ParameterTypeRequiredDescription
    ai_idstringone ofThe AI whose history to fetch. Mutually exclusive with group_id.
    group_idstringone ofThe group chat whose history to fetch. Mutually exclusive with ai_id.
    limitnumbernoPage size, 1–100. Defaults to 50.
    start_after_timestampnumbernoCursor; pass the previous page's lastTimestamp to continue.

    Exactly one of ai_id or group_id must be supplied.

  • Response:
    • Success: 200 OK with JSON:
      {
        "messages": [
          {
            "id": "string",
            "sender": "string",
            "sender_type": "string",
            "display_name": "string",
            "timestamp": 0,
            "message": "string",
            "image_urls": ["string"],
            "image_description": "string",
            "video_description": "string",
            "internet_response": "string",
            "link_url": "string",
            "link_description": "string"
          }
        ],
        "pagination": {
          "hasMore": true,
          "lastTimestamp": 0,
          "limit": 50
        }
      }

      Fields that are not present on a given message are omitted (image_urls may be null instead). To page, repeat the request with start_after_timestamp set to pagination.lastTimestamp until hasMore is false. Note that long-polling this endpoint may hit 429 and we recommend calling this when new messages have arrived. There is a 24 hour rate limit of 600 reqs/24 hrs due to the potential for this endpoint to be costly for us to serve.

    • Error: 400, 401, 403, 429, 500

Rewind Messages#

Removes the most recent messages from a conversation (an "undo"). Useful for discarding the last exchange before continuing.

  • URL: /rewind-messages
  • Method: POST
  • Request Body:
    {
      "ai_id": "string",
      "count": 1
    }
    FieldTypeRequiredDescription
    ai_idstringone ofThe AI to rewind. Mutually exclusive with group_id.
    group_idstringone ofThe group chat to rewind. Mutually exclusive with ai_id.
    countnumberyesNumber of most-recent messages to remove (1–10).

    Exactly one of ai_id or group_id must be supplied, and up to 10 messages can be removed per request. For single-AI rewinds (ai_id), the chat must end on an AI message both before and after the rewind. In a normal back-and-forth chat that means count must be even, removing whole user/AI exchanges; a count that would leave a user message last returns 400. Group rewinds (group_id) have no such restriction. Chat breaks, voice call messages, messages whose media is still generating, and messages beyond an earlier rewind's boundary can't be rewound and return 409.

  • Response:
    • Success: 200 OK with JSON listing what was removed: deleted_message_ids, deleted_record_ids, new_latest_message_id and rewind_floor_record_id.
    • Error: 400, 401, 403, 404 (AI/group not found), 409 (messages can't be rewound, or a voice call is active), 429, 500

Update AI Info#

Updates the persona and configuration of an existing AI. Only include the fields you want to change; omitted fields are left unchanged.

  • URL: /update-info
  • Method: POST
  • Request Body: (ai_id required; all others optional)
    {
      "ai_id": "string",
      "ai_name": "string",
      "ai_gender": "string",
      "ai_backstory": "string",
      "ai_memory": "string",
      "ai_directive": "string",
      "ai_example_message": "string",
      "ai_additional_context": "string",
      "current_scene": "string",
      "user_name": "string",
      "user_gender": "string"
    }
    FieldTypeDescription
    ai_idstringThe AI to update. Required.
    ai_namestringDisplay name of the AI.
    ai_genderstringGender of the AI.
    ai_backstorystringThe AI's backstory.
    ai_memorystringThe AI's key (long-term) memory.
    ai_directivestringDirective / response guidelines for the AI.
    ai_example_messagestringExample message defining the AI's voice.
    ai_additional_contextstringAdditional context (availability depends on plan).
    current_scenestringThe current scene / situation.
    user_namestringYour display name as seen by your Kindroids. Applies account-wide; a persona tied to a chat overrides it.
    user_genderstringYour gender as seen by your Kindroids. Applies account-wide; a persona tied to a chat overrides it.
    The underlying endpoint accepts additional fields used by the Kindroid apps (model selection, voice/call settings, beta flags, etc.). Those are considered internal and are not part of the supported external API surface.
  • Response:
    • Success: 200 OK
    • Error: 400, 401, 403, 429, 500

Group Chats#

Group chats let multiple Kindroids participate in a single conversation. Group chats can also use the Get Chat Messages and Rewind Messages endpoints above; pass group_id instead of ai_id.

Note: Group chats require an active subscription. Requests from non-subscribers return 403 Forbidden.

Create and configure groups in the Kindroid app; these endpoints operate on an existing group_id. A typical turn-based loop looks like:

  1. POST /groupchats-user-message: post the user's message.
  2. POST /groupchats-get-turn: ask who should speak next.
  3. If an ai_id is returned, POST /groupchats-ai-response for that AI, then go back to step 2. If the user's turn is returned (empty body), stop and wait for the next user message.

Group User Message#

Adds a user message to a group chat.

  • URL: /groupchats-user-message
  • Method: POST
  • Request Body:
    {
      "group_id": "string",
      "message": "string"
    }
    FieldTypeRequiredDescription
    group_idstringyesThe group chat.
    messagestringone ofThe user's text message. Provide either message or audio_url.
    audio_urlstringone ofStorage path of a voice message already uploaded to Kindroid (as the app does), not an external URL. Provide either message or audio_url.

    Exactly one of message or audio_url must be supplied.

  • Response:
    • Success: 200 OK
    • Error: 400, 401, 403, 429, 500

Group Get Turn#

Determines which participant should speak next in the group.

  • URL: /groupchats-get-turn
  • Method: POST
  • Request Body:
    {
      "group_id": "string",
      "allow_user": true
    }
    FieldTypeRequiredDescription
    group_idstringyesThe group chat.
    allow_userbooleanyesWhether the user is allowed to take the next turn (i.e. AI generation may end).
  • Response:
    • Success: 200 OK with the ai_id of the AI whose turn it is. An empty body indicates it is the user's turn (end of the AI generation cycle).
    • Error: 400, 401, 403, 429, 500

Group AI Response#

Generates a response from a specific AI in the group. Pair with Group Get Turn to drive the conversation.

  • URL: /groupchats-ai-response
  • Method: POST
  • Request Body:
    {
      "group_id": "string",
      "ai_id": "string",
      "stream": false
    }
    FieldTypeRequiredDescription
    group_idstringyesThe group chat.
    ai_idstringyesThe AI that should respond.
    streambooleannoStream the reply as it is generated.
  • Response:
    • Success: 200 OK. With "stream": true, the AI's reply is streamed as text as it is generated. Without it, the body is empty and the reply is only saved to the chat; read it with Get Chat Messages.
    • Error: 400, 401, 403, 429, 500

Group Chat Break#

Ends the current group conversation and resets short-term memory. A greeting is mandatory and becomes the first message in the new conversation.

  • URL: /groupchats-chat-break
  • Method: POST
  • Request Body:
    {
      "group_id": "string",
      "greeting": "string",
      "wipe_cascaded": false
    }
    FieldTypeRequiredDescription
    group_idstringyesThe group chat to reset.
    greetingstringyesFirst message of the new conversation.
    wipe_cascadedbooleannoAlso wipe the group's cascaded long-term memory built up from previous conversations. Defaults to false (only short-term memory is reset).
  • Response:
    • Success: 200 OK
    • Error: 400, 401, 403, 429, 500

Update Group Info#

Updates the configuration of an existing group chat. Only include the fields you want to change; omitted fields are left unchanged.

  • URL: /groupchats-update
  • Method: POST
  • Request Body:
    {
      "group_id": "string",
      "ai_list": ["string"],
      "group_name": "string",
      "group_context": "string",
      "group_directive": "string",
      "current_scene": "string"
    }
    FieldTypeRequiredDescription
    group_idstringyesThe group chat to update. Required.
    ai_liststring[]noThe AI IDs in the group (the roster). At least one.
    group_namestringnoDisplay name of the group.
    group_contextstringnoShared context / situation for the group.
    group_directivestringnoDirective / response guidelines for the group.
    current_scenestringnoThe current scene / situation.
  • Response:
    • Success: 200 OK
    • Error: 400, 401, 403, 429, 500

Discord Bot Endpoint#

Core endpoint for sending context and getting a response. Used in the Kindroid Discord bot. Requires an active subscription.

  • URL: /discord-bot
  • Method: POST
  • Request Headers:

    In addition to the Authorization header, you must send a header identifying the hashed, unique string of the Discord user who triggered the call; requests without it return 400. This helps with rate limiting and preventing bot abuse (each requester is limited to 10 requests per 30 seconds). Any hashing scheme works, but we recommend:

    const lastUsername = conversation[conversation.length - 1].username;
    // Encode username to handle non-ASCII characters, then hash to alphanumeric
    const hashedUsername = Buffer.from(encodeURIComponent(lastUsername))
      .toString("base64")
      .replace(/[^a-zA-Z0-9]/g, "")
      .slice(0, 32);

    Place it in the header as:

    X-Kindroid-Requester: <hashedUsername>
  • Request Body:
    {
      "share_code": "string",
      "enable_filter": true,
      "conversation": [
        { "username": "string", "text": "string", "timestamp": "string" }
      ]
    }
    FieldTypeRequiredDescription
    share_codestringyes5-character share code (see the Discord repo). Must be shared by the UID who is authenticating.
    enable_filterbooleannoContent filter. Recommended for public servers. Defaults to false.
    conversationarrayyesArray of { username, text, timestamp }. timestamp is msg.createdAt.toISOString().
  • Response:
    • Success: 200 OK with JSON: { "success": true, "reply": "string", "stop_reason": "string" }
    • Error: 400, 401, 403, 404 (share code not found), 429, 500