Bring your own storage (BYOS)

Before you begin

You need an Azure subscription with a storage account you administer: a StorageV2 account with hierarchical namespace enabled — that is, Azure Data Lake Storage Gen2 — and a container in it to receive the data. Prepare the storage account below covers both.

You also decide how TrueIdiom reaches that account: a role assignment for the recommended keyless managed identity, or a SAS token or connection string you paste once. See Choose an access mode.

Binding, verifying and removing the account are admin actions: they need a workspace admin, or the workspace’s API key. Every member can see the binding and its status, but a member’s change is refused with 403, and each change is recorded in the audit log with who made it — never the secret.

What moves to your account

Once your binding is verified, two data planes route to your storage:

A binding also carries a third prefix, terminology/, which is reserved for a future plane. Nothing writes to it today: terminology and translation memory currently stay in the platform control plane for every workspace, BYOS or not. A custom terminology prefix is accepted and stored on your binding, but it simply sits unused until that plane ships.

Approving a document does not add a record to golden/ in your account. It writes a counts-only audit record — document id, reviewer, language pair, how many segments, no text — to our side of the line. The document’s own files land in documents/ as usual.

Routing is fail-closed: data goes to your account only after the binding is verified, and nothing silently falls back to platform storage when your storage becomes unreachable. While the binding is not verified — including right after any edit — or cannot be used because its stored secret is missing or unreadable, new translations are refused up front with 409 storage_binding_not_verified, before any translation runs or any job is created, so nothing is charged; jobs that would have gone to review are refused too. What happens to a job already under way when your storage becomes unreachable depends on which pipeline it came from — a text translation job whose published result cannot be written parks with a persistence_failed status and is replayed for you once the binding is verified again (a parked job is billed: its translation is final and readable in the meantime), while a document job is marked failed and has to be resubmitted after you fix the binding — unless its translated file had already reached your account, in which case it is billed and its failure message says it does not need resubmitting. Scratch copies of the files that go to your account are removed once the upload has been attempted, and downloads are served from your account.

One artifact never leaves our side: the pipeline telemetry log. It is execution internals end to end — engine routing, per-stage model calls, per-stage token cost — with nothing in it you would read, so it is retained platform-side only and is never uploaded to your account. The layout JSONs, the quality report and the golden records that are written to your account are redacted copies: your text, geometry, review signals, scores and decisions are kept, while model names, token usage, reasoning and per-step agent metadata are stripped. Our full-fidelity copy stays in the platform control plane.

What stays with TrueIdiom

BYOS moves the translation data plane, not the whole service. Regardless of your binding, the platform control plane keeps your workspace and user accounts, billing and usage records, the job records themselves — including the source text and final translation of text jobs and the extracted text segments of documents — with their status and metadata (including checksums and review history), terminology and translation memory, the binding record itself, and — if you chose a secret-based access mode — the encrypted credential.

So BYOS decides where your published outputs and document files rest; it does not take your content out of the service’s own records. Translation and review still run on TrueIdiom compute, so text is processed on our side before the approved result is written to your account.

Prepare the storage account

  1. Create (or pick) a StorageV2 account with hierarchical namespace enabled — that is, Azure Data Lake Storage Gen2.
  2. Create a container to receive the data, for example golden. This becomes the binding’s filesystem.

Choose an access mode

Option A — Managed identity (recommended, keyless)

Grant TrueIdiom’s service principal the Storage Blob Data Contributor role on the container (or the account). Read the principal’s application ID straight from the API — GET /api/storage/binding returns it as principal_client_id, and works before you have bound anything:

curl -sS "$BASE_URL/api/storage/binding?api-version=2026-09-01" \ -H "Authorization: Bearer $TOKEN" | jq -r .principal_client_id

On the rare deployment where that comes back null, the identity is one we cannot name from configuration — ask us rather than guessing, because a role granted to the wrong principal fails as a plain permission error with nothing to point at it.

az role assignment create \ --assignee <trueidiom-sp-app-id> \ --role "Storage Blob Data Contributor" \ --scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<acct>/blobServices/default/containers/<container>"
Note: No secret ever changes hands — and revoking the role later cuts off TrueIdiom’s access. That is your kill switch, and it is entirely in your hands. Azure takes the same few minutes to propagate a revocation as it does a grant, so expect access to stop shortly after you revoke rather than on the instant.

Option B — SAS token

Generate a SAS token for the container with read, write, create, delete, and list permissions and a sensible expiry. You paste it once when binding; it is stored encrypted immediately and is never returned by any API or page afterwards.

Option C — Connection string

Handled exactly like a SAS token: stored encrypted, referenced indirectly, never displayed again.

Bind the account

As a workspace admin, open Storage (under Administration) in the workspace and enter: provider Azure Data Lake (adls), your account URL (https://<acct>.dfs.core.windows.net), the container name, and the access mode — pasting the secret if you chose SAS or connection string. Save.

The account URL has to be your storage account’s own endpoint: the dfs form above, or the account’s blob endpoint, which is saved as the dfs one — over https, with no port, path or query. Anything else, and any account TrueIdiom itself writes to, is refused with a 422 when you save. Saving checks the URL’s form, not that the account exists; that is what verify is for.

Always fill in the container name. The documents plane uses it verbatim, so a blank value leaves document jobs with nowhere to write.

Prefer the API? The same binding as a call — with an admin’s access token, or the workspace API key in X-API-Key:

curl -sS -X PUT "$BASE_URL/api/storage/binding?api-version=2026-09-01" \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{ "provider": "adls", "account_url": "https://myacct.dfs.core.windows.net", "filesystem": "golden", "auth_mode": "managed_identity" }'

For sas or connection_string, include a "secret" field — the response only ever confirms has_secret: true. On a later save with the same access mode you may leave the secret out to keep the one already stored. An optional "prefixes" object remaps the per-plane directories if you want something other than the defaults shown above.

This call is a full replace, not a patch: anything you leave out — the stored secret aside, as above — falls back to its default, so omitting prefixes resets your custom directories. Send the complete desired state every time. The full endpoint reference — reading the binding, replacing it, verifying, deleting, and the error shapes to branch on — is in the Storage API documentation.

Custom prefixes are API-only. The in-app Storage panel has no field for them, and because saving from it is the same full replace, a panel save silently resets all three prefixes to the defaults. If you set custom prefixes over the API, re-PUT them after anyone saves from the panel — and prefer the API for those workspaces.

Verify the binding

Verification is a real write/read/delete round-trip against your account using the binding’s credentials — not a formatting check. Wrong account URLs, missing role assignments, and expired SAS tokens all fail here. A failed probe is reported as a result, not as a transport error: the binding comes back with status error and a last_error field carrying Azure’s own message. Trigger it from the Storage section, or:

curl -sS -X POST "$BASE_URL/api/storage/binding/verify?api-version=2026-09-01" \ -H "Authorization: Bearer $TOKEN"

On success:

  • the binding flips to verified and live routing begins;
  • any text translation jobs that parked as persistence_failed while your storage was unreachable are replayed automatically, and the response includes a replay summary. Document jobs are not replayed — those you resubmit.

One caveat worth knowing before you scope permissions narrowly: the probe only writes under the golden/ prefix. Grant access to the whole container — or to every prefix you configure — so a passing verify actually means document artifacts will land too.

Caution: Every edit to a binding resets it to unverified. Re-run verify after any change — until you do, data does not route to your account and new translations are refused with 409 storage_binding_not_verified.

Day-to-day use

Nothing about the workflow changes. Translate, review, and approve as usual:

  • text translations you publish or approve land in golden/ in your container — one JSON record each plus a daily manifest;
  • document uploads and translated outputs land in documents/<job-id>/;
  • document downloads are fetched from your account.

One thing does change, in your favour: platform storage caps do not apply to you. Workspaces on platform storage can be given a ceiling on the document bytes they keep with us, and uploads past it are refused. Once your workspace is bound to your own account, that admission check is skipped entirely — those bytes rest in your account, on your subscription, and capacity planning is yours from there.

Opting out

Switch the binding back to the platform provider, or delete the binding entirely — either from the Storage section or via the API. Both drop any stored secret.

Caution: Data already written to your account stays there: leaving BYOS never migrates, copies back, or deletes what your account already holds. New work resumes on platform storage; the historical records remain yours to keep or clear on your own schedule.

Of the two, deleting the binding is the one provisioning never blocks. Switching back to the platform provider may first have to provision your platform storage container, and fails with a 502 if that does not succeed — a clean failure that changes nothing, leaving you on the binding you had — so reach for delete if the switch keeps failing. Either way out publishes any text jobs parked in persistence_failed to platform storage, with the same replay summary in the response as a verify.

Deletion you ask for is the one exception, and it is deliberate. When you delete a translation job or a document from TrueIdiom, the cascade also reaches into your bound account to remove that item’s records and artifacts there. That reach is best-effort and honestly counted: the removals it manages are reported in the response counts, and a failure on your side never blocks the platform-side delete. So if your storage is unreachable or our access has been revoked when you issue the delete, the copies in your account remain — and since the platform-side delete still completes, a second delete finds nothing to act on. Remove those copies from your account yourself: the job’s record under golden/ (and its line in that day’s manifest), or the document’s documents/<job-id>/ folder.

Troubleshooting

Stuck on something not listed here? Contact us and we will help you get storage set up.


What's next

  • Storage API reference — read, replace, verify and delete a binding, with the error shapes to branch on.
  • Pricing & billing FAQ — what a character is, and how plans, trials and top-ups work.
  • Getting started — the translate, approve and re-translate loop your golden files come from.