Skip to main content
What changes for your application: nothing, by default.Your own API keys receive real values, so the text you read back is identical to what you read before you protected anything. Aliases are what sits on our side. You only see one if you deliberately choose a setting that keeps the value from your app too, or issue a key that is restricted on purpose.

What an alias is

An alias is a stable placeholder that stands in for one sensitive value. It looks like this:
Three parts: who it belongs to, what kind of value it is, and twelve characters that make it unique. A support engineer reading PERSON_AADHAAR knows whose Aadhaar number is missing without looking anything up, which is the point of putting the readable part first. The twelve characters leave out the ones people confuse when reading a string aloud or copying it from a screenshot, so there is no 0 or O, no 1 or l or I. The leading word groups the alias by what it is about: PERSON, PAYMENT, HEALTH, PLACE, DEVICE, SECRET, or CUSTOM for a field type you defined yourself. When a memory carries an alias, the sentence around it still reads:
The event survives. Only the value is gone.

The same value always gets the same alias

This is the property everything else depends on. Two documents mentioning the same phone number produce the same alias, so anything that compares memories still works: deduplication still merges duplicates, a correction still supersedes the thing it corrects, and the entity graph still sees one identity rather than two. Before matching, Synap puts the value into a canonical form, so different spellings of the same thing collapse to one alias: An alias is shared at customer level, within one instance. Two users of the same customer who give the same phone number get the same alias, so a question that spans both their memories can still be answered. The same number under a different customer, or a different instance, gets a different alias, so nothing about one tenant’s data can be inferred from another’s.

Why search still works

This is the part that would break silently if it were not handled, so it is worth understanding. Your memory store holds [[PERSON_PHONE_h2n7v5cx8m0d]], not 9876543210. Someone searches for 9876543210. Every layer of retrieval is now looking for characters that are not there, and finds nothing. The product looks like it forgot, and the reason has nothing to do with memory quality. So your query goes through the same detection step your content did. Anything in it that your policy stores as an alias is swapped for that same alias before retrieval runs, and the search then looks for exactly what was written down. This is a hard requirement in the design, not an optimisation. Three rules keep that safe:
  • A query never creates an alias. It only looks one up. Searching for a value Synap has never seen leaves the query alone, which is the right answer: no memory holds that value either.
  • A query is rewritten only for field types you actually store as aliases. If your policy keeps real values for a field type, the store holds the real value and rewriting would break the search it is meant to fix.
  • A failed lookup never blocks a search. The query goes through untouched, which is the same answer as “we have never seen this value”.

What your application receives

On the way out, Synap puts real values back for exactly the field types the caller is entitled to, and leaves everything else as an alias. Entitlement is decided by two things, in this order:
  1. Your policy sets the ceiling. It is the “Your app gets” column of the settings table. Choose Protect at rest and your app gets real values. Choose Protect from everyone and it gets aliases.
  2. The grant on the API key that made the call can narrow that, and can never widen it. A key marked masked receives placeholders even for field types your policy would hand over.
An alias your caller is not entitled to is left exactly as it is. That is the correct answer rather than an error: the text is readable, the memory still says what happened, and your application was told which fields it would get back.
If you want to handle aliases explicitly, match on the shape: two square brackets, an uppercase label, an underscore, twelve lowercase alphanumeric characters, two closing brackets. Treat an alias as opaque, and never parse meaning out of the twelve characters.

Restricted keys and caching

If you use two keys with different grants against the same instance, the entitlement is part of what identifies a cached read, so a privileged fetch can never answer a restricted key’s request. Values are put back after the cache is read, never before, so nothing cached holds a real value.

Aliases and “do not store it”

A field type set to Do not store it still gets an alias, so the same value can be recognised when it appears again and occurrences can be counted. What it does not get is anything the value can be recovered from. A reveal on it returns nothing, for anyone, and the memory keeps a short description of what was taken instead of the value. Field types on the floor go further and get no alias at all, so there is nothing associated with them anywhere.

What this costs you

Reads pick up a small amount of extra work to look up and put values back, against a fetch that already takes far longer than that step. Ingestion picks up the detection pass, and ingestion is asynchronous, so you do not feel it in your request path. Every change to this feature is gated on the same benchmark suite Synap runs for retrieval quality, with a hard limit on how far any benchmark may move.

Next steps

Sensitive Data Protection

The categories, the six settings, and the floor.

Configure it

Set a policy, and test it before approving.

Erasing a person

What deleting someone makes unreadable, and what survives.

Sensitive data FAQ

Will this break my app, and what happens to memories I already have.