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

# Unreal SDK

> Install the Alakazam Portal Unreal plugin and generate programmable worlds and drop-in AI characters from Blueprint or C++.

The **Alakazam Portal** plugin brings the whole `/v1` surface to Unreal — generate and manage worlds, create talk-to characters, mint runtime sessions — plus a drop-in **Alakazam Character** component. Blueprint-first, with full C++ access. Requires **Unreal Engine 5.4+**.

## Install

<Steps>
  <Step title="Copy the plugin">
    Drop the `AlakazamPortal` folder into your project's `Plugins/` directory (`YourProject/Plugins/AlakazamPortal`).
  </Step>

  <Step title="Enable it">
    Open the project — Unreal prompts to build the plugin the first time. Confirm it's on under **Edit → Plugins → Alakazam Portal**, then restart the editor. Module dependencies (HTTP, Json) are declared by the plugin — nothing to add to your `Build.cs`.
  </Step>
</Steps>

## Setup

<Steps>
  <Step title="Open the Setup Wizard">
    The **Alakazam Setup Wizard** opens on first run. You can also configure the plugin any time under **Project Settings → Plugins → Alakazam Portal**.
  </Step>

  <Step title="Paste your key">
    Start with an `sk_test_…` secret key ([get one here](https://play.alakazam.gg/?view=developer)) — it runs a free, mocked [sandbox](/testing). Swap to `sk_live_…` when you ship.
  </Step>
</Steps>

<Warning>
  **Secret keys are editor/server-only.** Your `sk_` key can create worlds and mint sessions, so never ship it inside a packaged build. At runtime, a player talks to a world through a short-lived **session token** minted by your backend — the [two-token rule](/embedding).
</Warning>

## Programmable worlds & AI characters (`/v1`)

`UAlakazamClient` is a singleton wrapper over the [`/v1` API](/api-reference). Grab it with `UAlakazamClient::Get()` — in the editor it reads the key from **Project Settings**; on a server, set the key you loaded from your environment. Because Unreal's HTTP is asynchronous, every call takes a **completion callback**. The same calls are exposed as Blueprint nodes (category **Alakazam**).

```cpp theme={null}
#include "AlakazamClient.h"

UAlakazamClient* Client = UAlakazamClient::Get();

// Generate a world from a premise. Each call takes a TFunction completion callback
// (bool bSuccess, const FString& Json, int32 StatusCode) delivered on the GAME THREAD;
// turn the raw JSON into a typed struct with the matching Parse* helper.
Client->CreateWorld(TEXT("a neon rooftop at night"), TEXT(""), TEXT(""), TEXT(""),
    [](bool bSuccess, const FString& Json, int32 StatusCode)
{
    if (!bSuccess) return;
    const FAlakazamWorldResult World = UAlakazamClient::ParseWorldResult(Json);
    UE_LOG(LogTemp, Log, TEXT("world %s · slug %s · mock %d"),
        *World.WorldId, *World.Slug, World.bMock);
});
```

List, fork, edit, and import compiled worlds the same way — each takes the same completion callback:

```cpp theme={null}
Client->ListWorlds(20,        [](bool ok, const FString& Json, int32){ /* { worlds, nextCursor } */ });
Client->ForkWorld(WorldId,    [](bool ok, const FString& Json, int32){ /* { worldId } */ });
Client->EditWorld(WorldId, TEXT("add rain and a flickering sign"), [](bool, const FString&, int32){});
Client->ImportWorld(CompiledWorldJson, TEXT("My Level"), TEXT(""), [](bool, const FString&, int32){});
```

From Blueprint, use the dynamic-delegate nodes (**Create World**, **Mint Session**, **Character Say**) and the **Parse World Result** / **Parse Say Result** pure nodes.

<Note>
  A `sk_test_…` key returns **deterministic mocks** — every response carries `mock: true`, and nothing spends GPU or quota. Build your whole integration for free, then swap to `sk_live_…`. See [Testing](/testing).
</Note>

### Drop-in Alakazam Character

`UAlakazamCharacter` is an Actor Component that wraps the session → say → speak loop. Add it via **Add Component → Alakazam Character** on any actor, then set its properties in the Details panel (or from Blueprint / C++):

* **CharacterId** and **WorldId** — from a character you created (they're the same id).
* **SessionToken** — leave empty in the editor to mint one with your stored key (prototyping); **in a packaged build, assign a token minted by your backend** (the two-token rule).

Bind the Blueprint events — `OnReply`, `OnError`, `OnTtsAudio` — and call **Say**:

```cpp theme={null}
Character->CharacterId  = TEXT("chr_…");
Character->WorldId      = TEXT("chr_…");
Character->SessionToken = BackendMintedToken;   // production: minted by YOUR server

Character->OnReply.AddDynamic(this, &AMyActor::HandleReply);        // OnReply(FString reply)
Character->OnReplyDetail.AddDynamic(this, &AMyActor::HandleDetail); // OnReplyDetail(FAlakazamSayResult: stance, emotion, affect, action)
Character->OnError.AddDynamic(this, &AMyActor::HandleError);
Character->OnTtsAudio.AddDynamic(this, &AMyActor::HandleTtsBytes);  // OnTtsAudio(TArray<uint8> MP3 bytes)

Character->Say(TEXT("hello"));
```

<Note>
  **Voice is delivered as raw bytes, not auto-played.** Unreal has no built-in runtime MP3 decoder, so the component **broadcasts the raw `audio/mpeg` TTS bytes on `OnTtsAudio`** instead of playing them for you. Feed those bytes to a runtime audio importer (e.g. a runtime-audio-importer plugin) to get a `USoundWave` you can play. This is an honest engine difference: Unity decodes MP3 natively and auto-plays through an `AudioSource`; Unreal hands you the bytes.
</Note>

To create the character the component talks to (an editor/server step — needs the secret key) and mint the session token your backend would hand the client, use the same `UAlakazamClient::Get()` with `CreateCharacter`, `MintSession`, and `CharacterSay`. For a public, token-free share link to a *public* world, use `UAlakazamClient::PublicPlayUrl(Slug)`.

## `UAlakazamClient` reference

The Unreal client mirrors the [Unity `AlakazamClient`](/unity) and the [`/v1` contract](/api-reference) 1:1 — each method takes a completion callback (and is a Blueprint node under **Alakazam**).

| Method                                              | Auth           | Result                               |
| --------------------------------------------------- | -------------- | ------------------------------------ |
| `CreateWorld(premise, name?, frameUrl?, pov?)`      | secret         | `{ worldId, slug, cover, mock }`     |
| `ImportWorld(worldJson, name?, description?)`       | secret         | `{ worldId, slug, imported }`        |
| `FetchWorld(id)`                                    | secret         | world (graph nested under `world`)   |
| `ListWorlds(limit)`                                 | secret         | `{ worlds, nextCursor }`             |
| `ForkWorld(id)`                                     | secret         | `{ worldId }`                        |
| `EditWorld(id, instruction)`                        | secret         | `{ world, diagnostics, reply }`      |
| `LikeWorld(id)`                                     | publishable ok | —                                    |
| `CreateCharacter(name, premise, authored)`          | secret         | `{ id, slug, kind, mock }`           |
| `ListCharacters(limit)`                             | secret         | `{ characters, nextCursor }`         |
| `MintSession(worldId, playerIdentity?, origin?)`    | secret         | `{ token, expiresIn, slug }`         |
| `ConnectSession(sessionToken)`                      | session        | `{ worldId, reactorJwt, world }`     |
| `RefreshSession(sessionToken)`                      | session        | `{ reactorJwt, expiresIn }`          |
| `TrackSession(sessionToken, reactorSessionId)`      | session        | —                                    |
| `EndSession(sessionToken)`                          | session        | `{ ok, seconds }`                    |
| `CharacterSay(characterId, sessionToken, text)`     | session        | `{ reply, stance, emotion, action }` |
| `CharacterTts(characterId, sessionToken, text)`     | session        | raw `audio/mpeg` (MP3) bytes         |
| `CharacterImage(characterId, sessionToken, prompt)` | session        | `{ src, generated }`                 |
| `GetUsage()`                                        | secret         | `{ day, usage, caps, plan }`         |
| `PublicPlayUrl(slug)`                               | —              | `FString` (static helper)            |

<Note>
  Optional params at parity with Unity: `frame_b64` on **CreateWorld** / **CreateCharacter** (seed
  creation from a base64 image), `cursor` on **ListWorlds** / **ListCharacters** (pagination — pass the
  prior `nextCursor`), and `ttlSeconds` on **MintSession** (60–3600, sent only when > 0). The
  **Alakazam Character** component also fires an `OnConnected(bool)` event.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Unity SDK" icon="box" href="/unity">
    The same worlds + AI characters in Unity.
  </Card>

  <Card title="Characters" icon="user-round" href="/characters">
    Stances, memory, voice, and images in depth.
  </Card>

  <Card title="The two-token rule" icon="key-round" href="/embedding">
    Mint session tokens server-side; never ship a secret key.
  </Card>

  <Card title="Testing sandbox" icon="flask" href="/testing">
    Build the whole integration free with a test key.
  </Card>
</CardGroup>
