Data and privacy
What Amy keeps, who can see it, how to remove it, and what we do not claim.
Whose data is whose
- Organisations are isolated. Your API key reaches your organisation's data and
nothing else. Asking for another organisation's run, conversation or file gets
404, never403, so Amy does not even confirm it exists. - Your end users are isolated from each other by
endUserRef, the id you give each of your users on a run. It scopes conversations and memory (below). - Your clients are isolated too. A conversation belongs to the API
client and
endUserRefthat first used itsconversationId; a run or conversation another client or another end user started is a 404 for you.
endUserRef is an opaque id, never personal data
Send a stable pseudonymous id from your own system (a user id or an opaque token): up to 200 characters of printable ASCII with no spaces. Never put an email, name, phone number or government id in it. The reference is kept in webhook delivery logs and in the audit entries of every run (and of an erasure). Audit entries are kept 12 months, and erasure does not remove them or the reference in them (see below). The audit log also keeps the key an agent gives a memory (never its content), so personal data does not belong in memory keys either. Amy checks the shape of the value but cannot tell whether you have put personal data in it; that is your responsibility.
Memory
Memory is how an agent remembers facts across separate runs — a user's preferred language, an open question from last week. It is not part of the conversation transcript; it is a store the agent reads and writes with tools.
| Tool | What the agent does with it |
|---|---|
remember | Saves a fact under a short key (up to 200 characters). Saving under an existing key replaces it. |
recall | Searches saved facts for a question and returns the 5 best matches. |
list_memories | Lists saved facts by key (up to 100). |
forget | Deletes one saved fact by key. |
- Scope. A memory belongs to one combination of organisation, end user,
API client and agent. A fact saved while serving
user_8841is never recalled foruser_5527, and a fact saved by one agent is not visible to another agent, except that agents working together in a team run also see what their team has shared. Plan your agents with that in mind. - Always send
endUserRef. A run without one is not "no memory": it shares a single, unnamed memory with every other run that also omitted it (per organisation, client and agent). The agent's run-history tools refuse such runs instead. - Written by the agent, not by you. There is no API or Console page to read or write memory directly. The agent decides what to keep.
- Approvals. On the default agent, saving a fact is approval-gated and forgetting
one needs approval every time, so an unattended run pauses with status
awaiting_approval(a stream shows aneeds_approvalevent) when it tries. For an agent of your own, an Admin sets each tool's approval level on the agent's form (Agents). See Approvals. - Retention. A memory has no expiry. It lasts until the agent forgets it or you erase the end user (below).
- Search quality. Recall by meaning needs an Embeddings binding in AI Providers. Without one, facts are still saved and recall falls back to text search.
Conversations
By default a run is stateless: the agent sees only the new message. To have the agent
see earlier turns, send the same conversationId and endUserRef and set threadConversationHistory: true. Amy then replays only that client's earlier turns
for that end user (at most the newest 20 runs and 48,000 characters; see Limits). Your own UI can read a chat back with GET /v1/conversations.
What Amy keeps, and for how long
| Data | Kept | Removed by |
|---|---|---|
| Runs: messages, tool arguments and results, approvals | Amy does not delete them on a schedule. | End-user erasure. |
| Memory | No expiry. | forget, or end-user erasure. |
| Files you upload | Until you delete them — or, with Keep files sent by API keys off (Console → API keys), until every run that reads them has ended, or an hour after upload if no run used them. | DELETE /v1/files/{id}; end-user erasure, but only for files
attached to that end user's runs; or, once the switch is off, an Admin's Also delete the files already kept for the files sent before. |
| Files a run produced | With the run. | End-user erasure. |
| Usage records (tokens and ids, no content) | Kept for billing and your usage page. | Not removed by erasure. |
| Audit log (who did what; for example the key an agent gave a memory, and the reference in the entries of every run and of an erasure) | 12 months. | Expires on its own; not removed by erasure. |
| Webhook delivery log (the payloads sent: ids, never answers) | Until the endpoint is deleted. | Deleting the endpoint; not removed by erasure. |
Erasing an end user
When one of your users asks to be forgotten, an organisation Admin erases them in the Console
under End-user erasure, by their endUserRef (matched exactly, including case).
It is a Console action by design: an API key cannot erase an end user, so build the request into an
internal process in which an Admin carries it out.
It deletes, in one step:
- every memory saved for that end user, across all agents;
- their runs and everything under them — messages, tool calls and results, approvals, standing approvals granted for that user, and conversation titles;
- the files those runs produced, and the files you uploaded with
POST /v1/filesthat are attached to those runs, unless a run outside the erasure still uses them.
It keeps the usage records, the audit log and the webhook delivery log, which
hold only the pseudonymous reference and ids — which is why the reference must never be personal
data. It does not touch a file you uploaded but never attached to a run: delete those yourself
with DELETE /v1/files/{id}.
It does not reach the team-level record of a team run (goal, plan, step results, summary), a team's shared files, files a member uploaded in the Console, data in your own systems, or backups until they expire. A run still executing can write data after the erasure, so erase when the end user has no run under way, or repeat the erasure once it has finished.
The result reports a count for each kind of data removed. An erasure that removed anything is recorded in the audit log.
Inference privacy
Every model call sends your prompt to a model provider. An organisation Admin can restrict which providers may receive it, under Console → AI Providers → Organization → Inference privacy:
- Require verified zero data retention — only models that have a zero-retention endpoint on OpenRouter's current list, and the call is routed only to those endpoints.
- Deny training on your data — route only to providers that do not store or train on prompts.
The policy applies to every model call your organisation makes. A call that cannot meet it is
refused before anything is sent, with a 422. If the policy refuses a call after a
run has started, the run ends failed with the same code, and nothing is sent.
{
"title": "This organisation's privacy policy does not allow this request.",
"status": 422,
"detail": "Nothing was sent to the AI provider. An admin can bind a provider and model the policy allows in the Console under Providers.",
"code": "inference_policy_unsatisfied",
"condition": "model-no-zdr-endpoint"
}condition says why: provider-unconstrainable (the provider or the key's
endpoint cannot carry the restriction), model-no-zdr-endpoint, evidence-stale or no-evidence (the zero-retention list could not be confirmed; evidence older than 6 hours
counts as stale).
Check it from your own system
You do not have to take the Console's word for it. GET /v1/organisation/inference-privacy reports the policy and, for each capability, what is actually bound:
curl https://api.askamy.co.za/v1/organisation/inference-privacy \
-H "X-Api-Key: $AMY_API_KEY"{
"policy": {
"requireVerifiedZdr": true,
"denyDataCollection": true,
"updatedAt": "2026-10-12T09:14:03+00:00"
},
"enforced": true,
"evidence": {
"source": "openrouter-zdr-list",
"observedAt": "2026-10-15T07:02:11+00:00",
"stale": false
},
"capabilities": [
{
"capability": "chat",
"provider": "openrouter",
"model": "a-model-id",
"credentialScope": "org",
"retention": "zdr-verified",
"trainingUse": "verified-none",
"evidenceObservedAt": "2026-10-15T07:02:11+00:00",
"evidenceState": "verified"
}
],
"lastRouteViolationAt": null,
"routeAttribution": { "lastObservedAt": null, "lastUnattributedAt": null },
"generatedAt": "2026-10-15T08:30:00+00:00"
}enforcedistrueonly when a policy exists and every listed capability satisfies it right now.capabilitieslists exactlychat,visionandembeddings, each with the provider and model bound, whose key it uses (credentialScope:platform,orgornone),retention(zdr-verifiedornot-enforced),trainingUse(verified-noneornot-enforced) and anevidenceStatethat explains it.lastRouteViolationAtandrouteAttributionare alarms: they record the last time a call was seen to leave by a route the policy does not allow. They never changeenforced.
enforced cover chat, vision
and embeddings. OCR, speech and image generation are not listed, so enforced: true says
nothing about them. And it constrains what Amy sends to the provider you chose; it is not a statement
about your own systems or your MCP servers.How secrets are handled
| Secret | How Amy treats it |
|---|---|
| Your API key | Shown once. Amy stores only a SHA-256 hash of the secret half, compares in constant time, and cannot show it again. Revoking applies from the next request. |
| Your model provider keys | Stored encrypted and never shown again. |
Per-run MCP tokens (mcpAuth) | Used for that run, never stored and never logged. |
| Webhook signing secret | Shown when you create the endpoint or rotate it; never logged and not written to the audit log. |
Not covered here
This page describes how the API behaves. Contractual terms — where data is hosted, sub-processors, data-processing agreements — belong in your agreement with us. See also Privacy and Terms.