Skip to content

Protecting and Restoring Data

Your application protects a payload with one call to the AI Data Shield software development kit (SDK) and restores the values with another. Between the two, the text carries a surrogate in place of each protected value, so it can be stored, sent to a third party, or put in a prompt without the sensitive data going with it.

The calls are independent. Text protected in one exchange can be restored in a later one, by a different part of your application, if Shield policy allows it.

The SDK is published for Node.js and TypeScript as @altrsoftware/shield. It depends only on web platform APIs, so it also runs on edge platforms and in short-lived cloud functions.

A client needs 5 values. One names the endpoint, two identify the caller, one authenticates it, and one names the collection its protect calls classify against. All are set when you construct the client; a protect call can also set the collection for itself:

Value Where it comes from
The Data Plane URL The application’s details drawer, labeled Shield Base URL.
Your ALTR Organization ID The application’s details drawer, or Settings > Preferences.
The application identifier Assigned when you register the application.
The application’s RSA private key You generate the pair; ALTR holds only the public half.
A collection Any collection in the application’s allowed list. A protect call can also name its own, overriding the client’s.

See Registering an Application for the registration steps and where each identifier appears.

The private key is a PKCS#8 PEM file the SDK reads at run time – load it from a secret manager rather than committing it. The SDK signs a short-lived credential with it for each call, so there is no long-lived token to store or rotate.

A protect call submits the text. ALTR classifies it against the client’s collection, evaluates policy per finding, and returns the findings; the SDK splices them back into the text and hands your application the protected result.

The response reports everything Shield found, not only what it changed – each finding with its classifier, its position, and its action. A finding left alone appears with no action recorded, so your application can tell text that held nothing sensitive from text that held something Shield was not permitted to protect.

Your application can attach tags to the call. They are stamped onto every token it mints, and they are what lets a detokenization rule recognize where a token came from. See Shield Policy.

The SDK checks tags before it sends anything, so a malformed tag fails locally rather than after a round trip. The rules are the same everywhere a tag is supplied – see the grammar in Registering an Application.

A tokenized value is spliced back in as a self-closing XML tag carrying the token, in the form <altr tok="..."/>, standing where the value stood. The token is 64 characters of letters and numerals, and its casing is part of it – altering a letter’s case makes a different, unknown token. A tag rather than a bare string is what lets it survive a prompt, a conversation history, and a tool argument and still be found again: it is structurally distinct from the text around it, so nothing downstream reads it as prose.

The other two outcomes look different:

  • A masked value is spliced in as the masked literal by default, with no tag. Masking mints no token, so there is nothing to carry and nothing to restore. Your application can opt a masked value into a tag carrying context attributes, in which case the masked value sits between an opening and closing tag rather than in a self-closing one.
  • A value left in the clear is unchanged, byte for byte.

Restoration keys on the tok attribute and nothing else, so any other attribute your application adds – the matching classification, for instance – cannot break a round trip. A tag over 4,096 characters is not read as a tag at all: its token is never restored and the tag stays in the text.

A restore takes text containing token tags and returns it with the allowed values spliced back in. The SDK extracts the tokens and submits only those – the text itself never leaves your application. Shield evaluates the detokenization rules per token and returns only the values policy permits. A restore does not use the client’s collection: everything a rule can ask about a token was stored on it when it was minted.

A restore can carry tags of its own, which is what lets a rule compare the request against the token.

Anything not permitted is left as it was. A denied token stays in the text as its own tag, and so does a token Shield has never seen – deliberately indistinguishable, so a caller cannot use a restore call to learn whether a token exists.

Expect partial results. A restore call reports which tokens it restored and which it did not, and the returned text is safe to display either way: a token left in place is a surrogate, not sensitive data. Test whether a token resolved by comparing the returned value against the token itself, because an unresolved token maps to itself rather than to an empty value.

You can also pass the tokens directly, when your application holds them rather than the text around them. The SDK batches in groups of 100 distinct tokens and makes as many calls as it needs, so batch size is not yours to manage. Repeated tokens collapse first, so one token appearing many times costs one lookup.

Text streaming back from a model can be restored as it arrives. The stream transform the SDK provides passes token-free text through immediately and swaps each tag as soon as enough of it has arrived to read.

A tag split across two chunks is handled: the transform holds back only the part of a chunk that could still open a tag. A value never appears half-restored, and a tag is never flushed as visible text.

Both streaming forms take decoded text, not bytes – a byte chunk can end mid-character, so decode before the text reaches the transform.

You choose what a mid-stream failure does. The stream can stop, truncating a response the reader has already begun seeing, or keep going and pass the affected tags through as they are – a token carries no sensitive data, so the reader sees a surrogate instead. Pair that with the failure observer so a swallowed error is still visible.

A model that rewrites or drops a token tag breaks restoration. Instruct it to treat each <altr tok="..."/> tag as opaque and echo it back verbatim and inline, where the value belongs.

A model repeating a tag does not affect restoration. The tag is a surrogate, and restoration happens afterward under policy: a reader entitled to the value sees it, everyone else sees the tag.

Whether a repeated value keeps one token or collects a new one per occurrence is decided by the winning rule’s tokenization strategy, per finding – see Shield Policy. A deterministic strategy returns the token a value already has, so one value always carries one token – referential integrity across calls and conversations. A non-deterministic strategy mints a new token for every occurrence, so nothing links two of them. Tokens do not expire either way.

Under a deterministic strategy, “the same value” means the same value in the same determinism context – a scope your application sets, on the client or per protect call. The same value in two contexts produces two unrelated tokens, so the context is how you bound correlation: scope it to a tenant or a workload, and one tenant’s tokens tell you nothing about any other tenant’s values. Calls that set no context share one default scope across your whole organization. See the guessing caution under Shield Policy.

The context is a string of up to 256 bytes, and it is compared exactly as sent – never trimmed or case-folded, so Fruit and fruit are different scopes. Policy rules can match it on the restore side; the exact-match behavior matters there too, so settle on a fixed spelling wherever your code sets it. See Shield Policy.

The SDK retries what is worth retrying – connection problems, timeouts, rate limiting, and transient server faults – with a growing delay between attempts, honoring a server-supplied retry delay. A rejected credential is replayed once with a freshly signed one.

Restoring is safe to repeat – it is a read. Repeating a protect returns the same tokens under a deterministic strategy in the same determinism context; otherwise it mints new ones.

Three limits produce errors to handle rather than retry:

  • A protect request is rejected over 500,000 bytes of text. Split anything larger.
  • A determinism context is rejected over 256 bytes. The SDK checks before sending.
  • A restore whose results would be too large to return is rejected. The SDK splits the batch and retries before surfacing this.

A failed splice is reported as an error rather than returning text that might be wrong. The SDK never hands back a partially protected payload.

Errors carry the request identifier ALTR assigned, which is what ALTR support needs to trace a call. Log the safe summary form rather than the raw error: a validation error’s body reproduces the server response, which can quote fragments of the text you submitted.