Skip to content

Voice & realtime

ElevenLabs

ElevenLabs Conversational AI runs the voice agent on ElevenLabs' side and reaches your systems through server tools (webhooks it calls mid-conversation) and post-call webhooks (fired when a conversation ends). SurrealDB Agent Memory sits behind both: a server tool for recall during the call, and a post-call webhook to store the transcript. There is no dedicated adapter. You expose a small HTTP endpoint that forwards to SurrealDB Agent Memory.

Note

This is an integration guide. It shows the two webhook shapes ElevenLabs calls and how each maps to SurrealDB Agent Memory; wire them to your own hosting.

Add a server tool to the agent (for example recall_memory(query)) pointing at an endpoint you host. When the agent decides it needs context, ElevenLabs calls the tool and passes the return value back into the conversation. Handle it with the JavaScript SDK:

import { AgentMemory } from "@surrealdb/memory";

const memory = new AgentMemory({
    endpoint: process.env.AGENT_MEMORY_ENDPOINT!,
    context: process.env.AGENT_MEMORY_CONTEXT!,
    apiKey: process.env.AGENT_MEMORY_API_KEY!,
});

// POST /tools/recall (configured as an ElevenLabs server tool)
export async function POST(request: Request) {
    const { query, user_id } = await request.json();
    const block = await memory.context(query, {
        scope: [`org/acme/user/${user_id}`],
        k: 8,
    });
    return Response.json({ memory: block });
}

Pass the caller's user_id as a dynamic variable so the tool scopes recall to the right person.

Store the conversation with a post-call webhook

Configure a post-call webhook. ElevenLabs POSTs the full transcript when the conversation ends; store the turns so they are available next time:

// POST /webhooks/elevenlabs (post-call webhook)
export async function POST(request: Request) {
    const payload = await request.json();
    const { transcript, conversation_id } = payload.data;
    const userId = payload.data.metadata?.user_id ?? "anonymous";

    const turns = transcript.map((t: { role: string; message: string }) => ({
        role: t.role === "agent" ? "assistant" : "user",
        content: t.message,
    }));

    await memory.rememberMany(turns, {
        scope: [`org/acme/user/${userId}`],
    });

    return new Response("ok");
}
Important

ElevenLabs signs post-call webhooks with an HMAC header. Verify the signature against your webhook secret before trusting the payload.

Both endpoints scope to the caller with a slash path such as ["org/acme/user/alice"], derived from the dynamic variable or conversation metadata. Register paths with agent-memory scopes create before first use.

  • JavaScript SDK: the full client surface

  • REST API: calling SurrealDB Agent Memory over HTTP without the SDK

Was this page helpful?