> ## 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.

# Create a video mark

> Mint an id and a presigned URL for the mp4 you want checked.

`POST /api/video-marks/`

Returns an id and a 15-minute presigned `PUT` for `users/{user_id}/video-marks/{id}/input.mp4`. You upload the bytes. The object stays private.

Required headers:

* `Authorization: Bearer <YOUR_AKAPULU_API_KEY>`
* `Content-Type: application/json`

The body is exactly:

```json theme={null}
{
  "content_type": "video/mp4"
}
```

```json theme={null}
{
  "id": "11111111-2222-3333-4444-555555555555",
  "upload_url": "https://...",
  "s3_key": "users/1/video-marks/11111111-2222-3333-4444-555555555555/input.mp4",
  "content_type": "video/mp4",
  "expires_in": 900
}
```

`PUT` the file to `upload_url` with `Content-Type: video/mp4`. Then [read the mark](https://docs.akapulu.com/api-reference/video-marks/read.md).

The file must be an mp4 of at most 200MB. A different content type on this call is `400` `VALIDATION`.


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