Add memory

Enable memory on an agent and ground calls with the memory placeholder

Memory lets an agent recall durable facts about a caller across calls. For how it works, see Memory.

1

Enable memory on the agent

Toggle memory in the console, or PATCH the agent:

memory_retention_days bounds how far back retrieval reaches; 0 means no cap. It controls relevance, not erasure - use a delete to remove a fact.

2

Reference the placeholder in the prompt

Add {{memory}} where you want the facts grounded. The retrieved block is already a numbered list, so keep the surrounding prompt short.

You are a support agent for Acme. Speak concisely.
{{memory}}
Greet the caller, confirm what they need, and escalate only if you can't resolve it in one turn.

With memory disabled, the placeholder is stripped - no literal braces reach the LLM.

3

Pass a stable caller identity

Memory pivots on caller_identity, which is separate from the short-lived realtime participant identity:

  • Authenticated conversation creation - pass user_identity on POST /v1/agents/{id}/conversations. If omitted, user_<authenticated principal> remains the fallback caller key for backward compatibility.
  • Public widget - pass user_identity yourself, such as your own opaque user ID or a hashed email.
$curl -X POST "https://api.speechify.ai/v1/agents/$AGENT_ID/conversations" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"user_identity":"acme_user_42"}'
1<speechify-agent
2 agent-id="agent_01H..."
3 user-identity="acme_user_42">
4</speechify-agent>

Pick something stable and opaque: your own user ID or a hashed email, not an email address or a phone number you might reformat later. It may not begin with embed_, anon_ or user_ - those are reserved. Anonymous sessions - no identity supplied - are skipped by memory entirely.

A memory is only as trustworthy as the identity it was filed under. When your backend calls the API, we have authenticated you, so the identity you send is stored verbatim and the same value means the same person across your backend calls.

A public widget in a browser is different: nobody verified that claim, so those sessions get their own separate caller namespace. It means a visitor who edits the page cannot make the agent recall a different person’s memories - but it also means the widget and your backend do not share one caller record for the same human.

If one caller record per human matters to you, mint the session from your backend with POST /v1/agents/{id}/sessions (or /conversations) once you have authenticated the user, and hand the returned token to the browser. Then the identity is one you vouched for.

See Embed for the widget attribute. The realtime token carries a separate, per-session participant identity, so your caller key never reaches the browser.

4

Verify it end to end

  1. Give the agent a prompt containing {{memory}} and enable memory.
  2. Place a test call and state something durable - “I can only do mornings; I’m vegetarian.” Hang up.
  3. On the conversation detail page, Memories written this call lists the facts within about ten seconds.
  4. Call again as the same caller and ask an open question - the agent should use the fact without re-asking.

Manage memories

$# List a caller's memories
>curl https://api.speechify.ai/v1/agents/$AGENT_ID/memories \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY"
>
># Delete every memory for one caller
>curl -X POST https://api.speechify.ai/v1/agents/$AGENT_ID/memories/delete \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"agent_id":"'"$AGENT_ID"'","caller_identity":"acme_user_42"}'

Troubleshooting

Confirm {{memory}} is literally in the prompt. Without the placeholder, facts are stored but never injected.

The caller must be identified. Anonymous widget sessions (no user_identity) aren’t recorded - check the conversation’s caller_identity (empty means anonymous).

Retrieval has a 0.5 confidence floor. Lower-confidence facts show in the admin list but never enter the {{memory}} block.

Both calls need the same caller_identity. A widget embed that passes a different userIdentity counts as a different caller.

Usually fine - the extractor emits zero rather than invent filler, so mundane calls often produce none.