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

# Vapi

> Give a Vapi voice agent a memory it keeps: your knowledge, the lessons it learns from calls, and optional per-caller memory.

# Vapi + Memanto

<img src="https://mintcdn.com/memanto/y3z1OQlaycNoW40F/logo/integrations/vapi.svg?fit=max&auto=format&n=y3z1OQlaycNoW40F&q=85&s=9aa2f6c7455a91c4df8a9d60663ea2c6" alt="Vapi" width="64" style={{marginBottom: "1.5rem"}} data-path="logo/integrations/vapi.svg" />

A [Vapi](https://vapi.ai) assistant starts every call from zero. It doesn't know your policies unless they are in the prompt, and it repeats on Friday the mistake it was corrected for on Monday.

**`memanto-vapi`** is a single webhook that gives the assistant a memory it keeps between calls.

<CardGroup cols={2}>
  <Card title="Knowledge at call start" icon="brain">
    Your organization's knowledge and the lessons learned so far arrive in the prompt as `{{memanto_context}}`.
  </Card>

  <Card title="Memory tools mid-call" icon="wrench">
    `memanto_recall` looks things up; `memanto_remember` saves what the agent learns.
  </Card>

  <Card title="Learns from each call" icon="graduation-cap">
    At `end-of-call-report` the conversation becomes typed memories — mistakes, corrections, better answers, facts.
  </Card>

  <Card title="Never delays a call" icon="stopwatch">
    Lookup is capped at 3s inside Vapi's 7.5s `assistant-request` budget, and fails open.
  </Card>
</CardGroup>

## How It Works

```text theme={null}
Call starts  →  assistant-request  →  recall  →  {{memanto_context}} in the prompt
                                                        │
During call  →  tool-calls        →  memanto_recall / memanto_remember
                                                        │
Call ends    →  end-of-call-report → extract typed memories → Memanto
```

Everything lives in one Memanto agent, so you can read, correct, and audit what the voice agent knows with the [CLI](/cli/overview) or the web UI.

## Two scopes

<Tabs>
  <Tab title="shared (default)">
    One memory for the whole assistant: your knowledge plus the lessons from every call. Every caller benefits from what the agent learned yesterday, and no personal caller details are stored, so nothing can leak between callers.

    ```bash theme={null}
    MEMANTO_VAPI_SCOPE=shared
    ```
  </Tab>

  <Tab title="caller">
    Everything above, plus memories only that caller sees: their preferences, open issues, and commitments made to them. Their tag is an HMAC of `customer.number` (or `customer.externalId` for web and chat calls) keyed with a salt you set, so raw phone numbers are never stored.

    ```bash theme={null}
    MEMANTO_VAPI_SCOPE=caller
    MEMANTO_VAPI_CALLER_SALT=$(openssl rand -hex 32)
    ```
  </Tab>
</Tabs>

In caller scope the context has two parts:

```text theme={null}
Knowledge and lessons learned:
- [instruction] Refund window: refunds are accepted within 30 days (2026-09-01)
- [error] Do not quote weekend hours as 9-5; they are 10-4 (2026-09-14)

About this caller:
- [preference] Prefers morning delivery slots (2026-08-02)
- [commitment] Promised a callback about invoice 4471 (2026-09-15)
```

<Warning>
  Keep `MEMANTO_VAPI_CALLER_SALT` secret and stable. Changing it cuts every caller off from their existing memories.
</Warning>

The **server** decides whose memories a call may read and write, from the caller Vapi reports. The model never passes a caller ID, so a prompt injection cannot reach another caller's memories, and every result is re-checked against the caller's tag before it is returned. In caller scope, anything the agent saves mid-call is private to the caller on the line; shared lessons come only from end-of-call extraction, whose prompt excludes caller details.

## Prerequisites

* Python **3.10+**
* Memanto **0.2.21+** and a [Moorcheh API key](https://console.moorcheh.ai/api-keys) (or an on-prem Memanto backend)
* A Vapi account, a saved assistant, and a public HTTPS URL for the webhook

## Install and run

<Steps>
  <Step title="Install">
    ```bash theme={null}
    pip install memanto-vapi
    ```

    Until `memanto-vapi` is on PyPI, install it from a checkout of the Memanto repo: `pip install ./integrations/vapi` (see [GitHub source](https://github.com/moorcheh-ai/memanto/tree/main/integrations/vapi)).
  </Step>

  <Step title="Configure">
    ```bash theme={null}
    export MOORCHEH_API_KEY=your_key_xxxxxxxxxxxxxxxxxx
    export MEMANTO_VAPI_AGENT_ID=acme-support        # Memanto agent for this assistant
    export MEMANTO_VAPI_SECRET=$(openssl rand -hex 32)
    export MEMANTO_VAPI_ASSISTANT_ID=your_vapi_assistant_id
    ```
  </Step>

  <Step title="Serve">
    ```bash theme={null}
    memanto-vapi serve --port 8080
    ```

    The webhook is at `POST /vapi/webhook`, with `GET /health` for status. For local testing, expose it with `ngrok http 8080`.
  </Step>
</Steps>

The Memanto agent is created on first start. Run **one instance per agent** — Memanto keeps one active session per agent, so instances sharing `~/.memanto` would sign each other out.

## Load your knowledge

Anything stored in the Memanto agent is available to the voice agent. Add it before starting the webhook — activating an agent elsewhere signs out a running webhook until its next call:

```bash theme={null}
memanto agent activate acme-support
memanto remember "Refunds are accepted within 30 days of delivery" --type instruction
memanto upload handbook.pdf
```

Review and correct what the agent learned in the same place:

```bash theme={null}
memanto recall "weekend hours"
memanto edit <memory-id> --content "Weekend hours are 10-4"
```

## Configure Vapi

<Steps>
  <Step title="Create a credential">
    In the Vapi dashboard, create a **Bearer Token** credential whose token is `MEMANTO_VAPI_SECRET`. Requests without it are rejected with `401`; the legacy `X-Vapi-Secret` header is also accepted.
  </Step>

  <Step title="Create the tools">
    ```bash theme={null}
    memanto-vapi tools --server-url https://your-host/vapi/webhook --credential-id <credential id>
    # add --scope caller if the webhook runs in caller scope
    ```

    Create each printed definition with `POST https://api.vapi.ai/tool`, then add both tool IDs to the assistant's `model.toolIds`.
  </Step>

  <Step title="Use the variable in the prompt">
    ```text theme={null}
    What you know from earlier calls:
    {{memanto_context}}

    Use memanto_recall when you are unsure how to answer or handle a request.
    Use memanto_remember when you are corrected, or you learn something that
    would help on future calls.
    ```
  </Step>

  <Step title="Point Vapi at the webhook">
    Set the URL and credential **on the phone number**, so inbound calls ask it which assistant to use (don't also attach an assistant to the number), and **on the assistant** (`server.url`) with `end-of-call-report` in `serverMessages`, so calls are learned from.
  </Step>
</Steps>

## Outbound, web, and chat calls

Vapi only sends `assistant-request` for inbound phone calls. For calls you start yourself, build the overrides at call creation:

```python theme={null}
from memanto.cli.client.sdk_client import SdkClient
from memanto_vapi import VapiMemory

memory = VapiMemory(SdkClient(api_key=...), agent_id="acme-support")

overrides = await memory.build_assistant_overrides({})
# caller scope — pass the person:
# await memory.build_assistant_overrides({"customer": {"number": "+15551234567"}})

# POST https://api.vapi.ai/call
#   {"assistantId": ..., "customer": ..., "assistantOverrides": overrides}
```

Tools and end-of-call learning work the same for these calls. In caller scope the call must carry `customer.number` or `customer.externalId` for the caller's private half; the shared half always works.

## Mount in your own app

```python theme={null}
from fastapi import FastAPI
from memanto_vapi import VapiMemory, create_router

memory = VapiMemory(client, agent_id="acme-support")
app = FastAPI()
app.include_router(create_router(memory, secret=SECRET, assistant_id=ASSISTANT_ID))
```

Unlike `create_app`, `create_router` does not activate the Memanto session at startup — call `memory.ensure_ready()` in your own startup hook so the first caller doesn't wait for it.

## Behavior and limits

| Behavior                           | Detail                                                                                                                                       |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Fail-open recall**               | Capped at `recall_timeout` (3s). On timeout or error the call starts with an empty `{{memanto_context}}` and a warning is logged.            |
| **Bounded context**                | `recall_limit` (10) recent and 10 relevant memories per section, `max_context_chars` (4000) in total.                                        |
| **Background learning**            | `end-of-call-report` is acknowledged immediately and processed afterwards. Calls where the caller never spoke are skipped.                   |
| **No caller data in shared scope** | The extraction prompt excludes personal details, and `memanto_remember` stores everything as shared. Use caller scope for per-person memory. |
| **Retries are ignored**            | End-of-call memories carry a `retained-<call id>` tag, so a webhook Vapi re-delivers is not learned from twice.                              |
| **Possible duplicates**            | Within one call something can be saved twice — once by the tool while talking, once by extraction at the end.                                |
| **Reserved tag prefix**            | Tags starting with `caller-` mark private memories; shared lookups skip anything carrying one.                                               |
| **Agent-wide analysis**            | Conflict scans and daily summaries cover the whole agent, including every caller's memories in caller scope.                                 |

## Shared memory across integrations

All Memanto integration packages use the same Moorcheh-backed agents when they share an `agent_id`:

| Integration                                         | Package             | What it does                                                                          |
| --------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------- |
| **Vapi**                                            | `memanto-vapi`      | Webhook giving a Vapi voice agent knowledge, lessons, and optional per-caller memory. |
| [`integrations/mcp`](/integrations/mcp)             | `memanto-mcp`       | MCP server for Claude Desktop, Cursor, etc.                                           |
| [`integrations/agentcore`](/integrations/agentcore) | `memanto-agentcore` | Recall/retain wrapper for Bedrock AgentCore Runtime handlers.                         |
| [`integrations/crewai`](/integrations/crewai)       | `crewai-memanto`    | CrewAI tools for multi-agent memory.                                                  |
| [`integrations/langgraph`](/integrations/langgraph) | `langgraph-memanto` | LangGraph `BaseStore`, nodes, and tools.                                              |

## Next Steps

* [Vapi integration source & README](https://github.com/moorcheh-ai/memanto/tree/main/integrations/vapi)
* [Vapi server URL events](https://docs.vapi.ai/server-url/events)
* [Remember API](/api-reference/data/remember)
* [Recall API](/api-reference/search/recall)
