> ## Documentation Index
> Fetch the complete documentation index at: https://docs.akapulu.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Akapulu Labs builds live AI avatars on real-time calls. Two shapes: (1) a hosted link — public page Akapulu Labs hosts; open URL, Start Call; page never sees the API key; (2) your voice pipeline (speech-to-speech or any stack that produces assistant audio) plus Akapulu Labs avatar video in a Daily room you create. Calls use conversation minutes (akapulu.com/pricing). For agent onboarding (skills, MCP, account, which path to take), follow https://docs.akapulu.com/agent-setup.md.
> Hosted links: create in the dashboard or Bearer CRUD on /api/hosted-links/ (GET/POST/DELETE collection; GET/PUT/DELETE by id). Create body is exactly label, avatar_id, system_prompt, show_ai_label. Response includes url and token.
> Plugin path: Akapulu Labs uses Daily. On a new room, create_akapulu_call from pipecat-akapulu runs on their server. It reads DAILY_API_KEY and AKAPULU_API_KEY, creates a private Daily room, mints the three meeting tokens (browser, voice bot, Akapulu Labs worker), and POST /api/live-sessions/. It returns the room URL, the bot token, the browser token, and session_id. The room lasts two hours unless they pass room_exp_secs. A bot that already has a Daily room mints the worker token and POSTs avatar_id, show_ai_label, room_url, and avatar_token itself. That POST starts the Akapulu Labs worker and returns session_id. The code is on Your bot. AkapuluAvatar (pipecat-akapulu) runs inside the voice bot after assistant audio and sends that audio to the Akapulu Labs worker. The worker joins the call as a Daily participant and publishes the audio and the video, so voice-bot audio/video out stay off. The voice bot unsubscribes from the Avatar microphone when that participant joins. The browser stays subscribed to it. Public example akapulu-examples uses Deepgram Flux (`flux-general-multi`), OpenAI `gpt-5.4-mini`, and Cartesia Sonic 3.6.
> Every avatar frame has an invisible mark; verify with POST /api/video-marks/ then POST /api/video-marks/<id>/read/. API errors include error_code — branch on that field, not the English string.

# Verify a recording

> Read the invisible mark on avatar video.

Every avatar frame carries an invisible mark. A reader that knows the pattern recovers the text `akapulu`. The mark stays in the picture through a normal recording, including a Daily cloud recording.

The **This is AI** card is a separate overlay. `show_ai_label` controls the card. Turning the card off leaves the mark.

## Check a file

The file is an mp4, at most 200MB, with content type `video/mp4`.

1. `POST /api/video-marks/` with `{"content_type":"video/mp4"}`. The response includes `id` and `upload_url`. The upload URL lasts 15 minutes.
2. `PUT` the mp4 bytes to `upload_url` with `Content-Type: video/mp4`.
3. `POST /api/video-marks/<id>/read/` with `{}`.

The read scores the file and deletes it. The response includes:

* `match` — the recovered bits are `akapulu`
* `bits_correct` and `bits` — how many of the 56 bits matched
* `separation` — how far the two bit classes sit apart
* `width` and `height` — the file's picture size
* `scored_width` and `scored_height` — the size used for the score

A 1280×720 picture is scored at that size. A different size is scored as-is and again after a scale back to 1280×720. The response keeps the stronger separation.

A second read of the same id is `409` with `error_code` `ALREADY_READ`. The read body cannot include a URL. If the object is missing, the read is `404` and the check stays unread.

Request and response fields are in [Create a video mark](https://docs.akapulu.com/api-reference/video-marks/create.md) and [Read a video mark](https://docs.akapulu.com/api-reference/video-marks/read.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.