Workflows
Export configuration
Back up or migrate the settings, transcription terms and templates of a user, clinic or organization, including retained template versions.
The configuration export gives you a machine-readable copy of how Vetnio is set up: personal preferences, clinic and organization settings, transcription terms, and every template with its stored history. Use it to back up a clinic's setup, to keep a change history in your own systems, or to move to or from Vetnio. All endpoints are read-only.
It does not cover clinical data (consultations, transcripts, notes, recordings); use Export clinical data for those. Usage statistics are in Export usage statistics.
Before you start
You need a personal API key (sk_live_…) of a user with the right role for each scope. Organization and clinic keys (sk_org_…, sk_ws_…) get 403 This API key cannot access this endpoint on every endpoint in this guide. See Authentication.
| Scope | Endpoints | Who can call them |
|---|---|---|
| Your own user | GET /users/me/data-export/content | Any user, for themselves only |
| A clinic | GET /workspaces/{workspaceId}/data-export/… | A clinic admin or superadmin, or an admin of an organization the clinic belongs to |
| An organization | GET /organizations/{organizationId}/data-export/… | An organization admin or superadmin |
Each scope exports only its own settings. A clinic export does not include the organization's settings or any person's personal settings, and other users' preferences can only be exported by those users.
What is exported
| Endpoint | Contents |
|---|---|
GET/users/me/data-export/content | Your name, personal preferences such as default recording language, note editor settings and your custom AI instructions, and your personal transcription terms |
GET/workspaces/{workspaceId}/data-export/content | The clinic's name, address and contact details, shared settings (consultation visibility, template permissions, document header, PDF letterhead and its logo, global template instructions, recording and phone-call settings), practice-system department mappings, the Catalog's Suggest and Search switches and notes for Vetnio on catalog items and bundles (only when the clinic has set any), and the clinic's transcription terms |
GET/organizations/{organizationId}/data-export/content | The organization's name, address, custom domains, preferences (such as billing presentation and the default recording view and live transcription for its clinics), audio retention policy and the organization's transcription terms |
GET/workspaces/{workspaceId}/data-export/templates | The clinic's templates for clinical notes, client communications and referrals |
GET/workspaces/{workspaceId}/data-export/json-templates | The clinic's structured templates (Vetnio calls them JSON templates), in their original JSON form |
GET/workspaces/{workspaceId}/data-export/meeting-templates | The clinic's meeting templates |
GET/organizations/{organizationId}/data-export/templates | The organization's template blueprints, which it can share to its clinics |
Credentials, API keys, billing-provider identifiers and internal state are never included. Vetnio's built-in default templates are left out; copies a clinic made of them are included.
1. Export your own settings
GET/users/me/data-export/content takes no parameters. Send none: unlike other endpoints, this one rejects unknown query parameters with 400.
curl https://vetnio.com/api/v2/users/me/data-export/content \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"schemaVersion": 1,
"exportedAt": "2026-10-04T16:25:40.364Z",
"scopeId": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"termList": {
"terms": ["Bravecto", "Librela", "Cytopoint"],
"version": 1,
"updatedAt": "2026-10-04T16:25:34.317Z",
"updatedBy": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7"
},
"inventory": {
"included": [
"User identity and allowlisted personal preferences",
"Current personal transcription term list"
],
"excluded": [
"Credentials, API keys, OAuth/session/password material and provider connection secrets",
"…"
],
"limitations": [
"Current stored values only; separate reads do not form an atomic snapshot",
"…"
]
},
"scope": "user",
"configuration": {
"id": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"name": "Alex Demo",
"preferences": {
"colorMode": "light"
}
}
}Every configuration export has the same envelope:
| Field | Meaning |
|---|---|
schemaVersion | The format version of this export, currently 1. |
exportedAt | When the export was produced. |
scope, scopeId | user, workspace or organization, and the ID. |
configuration | The stored settings. A setting nobody has changed is absent or null; Vetnio does not fill in its defaults. |
termList | The Transcription terms for this scope: the words Vetnio should recognize when it transcribes, such as product names. version goes up by one with every saved change and is 0 when no list was ever saved; it is a change counter, and earlier lists are not kept. |
inventory | Plain-language lists of what the export includes and excludes, and how to interpret it. |
2. Export a clinic's settings
curl https://vetnio.com/api/v2/workspaces/demo-north-clinic/data-export/content \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"schemaVersion": 1,
"exportedAt": "2026-10-04T16:25:06.152Z",
"scopeId": "demo-north-clinic",
"termList": { "terms": [], "version": 0, "updatedAt": null, "updatedBy": null },
"inventory": { "included": ["…"], "excluded": ["…"], "limitations": ["…"] },
"scope": "workspace",
"configuration": {
"id": "demo-north-clinic",
"name": "DEMO North Clinic",
"createdAt": "2026-09-08T09:00:00.000Z",
"address": null,
"city": null,
"stateProvince": null,
"zipCode": null,
"countryCode": "SE",
"taxId": null,
"phone": null,
"allowPasswords": true,
"templatePermissions": "full_access",
"audioFileRetentionPeriodInDays": null,
"isMeetingsEnabled": false,
"manualPimsKind": null,
"manualPimsName": null,
"settings": {},
"pimsDepartmentMappings": [],
"letterheadAsset": null
}
}settings holds the clinic's shared settings and is empty here because this clinic has changed none. When the clinic has a logo on its PDF letterhead, letterheadAsset holds it as a PNG: { "mimeType": "image/png", "encoding": "base64", "content": "iVBORw0…" }. Decode content from base64 and save it as a .png file.
A clinic member who is not an admin gets 403:
{
"message": "You are not an admin of this workspace",
"code": "FORBIDDEN",
"data": { "code": "FORBIDDEN", "httpStatus": 403, "path": "customerContent.workspaceConfiguration", "zodError": null }
}3. Export an organization's settings
curl https://vetnio.com/api/v2/organizations/83222a0a-688b-413e-9761-146f7a173b58/data-export/content \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"schemaVersion": 1,
"exportedAt": "2026-10-04T16:35:20.000Z",
"scopeId": "83222a0a-688b-413e-9761-146f7a173b58",
"termList": { "terms": [], "version": 0, "updatedAt": null, "updatedBy": null },
"inventory": { "included": ["…"], "excluded": ["…"], "limitations": ["…"] },
"scope": "organization",
"configuration": {
"id": "83222a0a-688b-413e-9761-146f7a173b58",
"name": "DEMO Clinic Group",
"address": null,
"customDomains": [],
"audioFileRetentionPeriodInDays": null,
"createdAt": "2026-10-04T16:27:15.461Z",
"updatedAt": "2026-10-04T16:27:15.461Z",
"preferences": {}
}
}No endpoint lists a user's organizations. The example request in the For developers section of Organization → API contains the organization's ID, and so does the request that Use via API builds in the Export dialog.
4. List templates
The four template endpoints return one page of templates at a time, with their metadata and a download link for each stored body. Pass limit (1 to 50, default 20), and continue with cursor set to the previous page's nextCursor until nextCursor is null. Pages are ordered by template ID. Pagination explains cursors in detail.
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/data-export/templates?limit=2&cursor=acf5c844-9762-4be9-9a89-e113f5c6e3df" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"nextCursor": null,
"expiresInSeconds": 3600,
"expiresAt": "2026-10-04T17:44:53.092Z",
"items": [
{
"id": "e21f9df7-d51c-4e6f-bf40-adb22b8096d0",
"workspaceId": "demo-north-clinic",
"name": "Dental check - export guide",
"type": "clinical_note",
"creatorId": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"creatorRole": "admin",
"createdAt": "2026-10-04T16:25:53.950Z",
"updatedAt": "2026-10-04T16:25:59.327Z",
"updatedBy": "c1b0f2a0-f819-5fcc-a2ed-85db0cef66a7",
"isManaged": false,
"isDefault": false,
"jsonTemplateId": null,
"hasExcludedJsonTemplate": false,
"instructionsArtifact": null,
"artifact": {
"contentUrl": "https://storage.example.com/templates/demo-north-clinic/e21f9df7-d51c-4e6f-bf40-adb22b8096d0?versionId=67249fb34e849e724253a5c3a56fde59&X-Amz-Expires=3600&X-Amz-Signature=…",
"currentVersionId": "67249fb34e849e724253a5c3a56fde59",
"contentType": "text/html",
"size": 298,
"lastModified": "2026-10-04T16:25:59.000Z"
}
}
]
}The fields that matter most:
| Field | Meaning |
|---|---|
type | Note templates only: clinical_note, client_communication or referral. |
isManaged | true when the clinic's organization, a practice-system integration or Vetnio provisioned the template, rather than a clinic user writing it. Managed templates are included. |
jsonTemplateId | The structured template this note template uses, when that structured template belongs to the same clinic. Keep the link when you rebuild templates elsewhere. |
hasExcludedJsonTemplate | true when the template uses a structured template that is not part of this clinic's export, such as a Vetnio default. |
artifact | The current body: a signed contentUrl, its currentVersionId, contentType, size in bytes and lastModified. null when no body is stored. |
instructionsArtifact | Note and meeting templates imported into Vetnio: the original wording and per-section instructions, as JSON. null when there are none. |
Structured templates carry id, workspaceId, name, creatorId, createdAt and artifact. Meeting templates add instructionsArtifact. Organization templates carry organizationId, type, createdBy and createdAt.
5. Download the bodies
Download each contentUrl with a plain GET, without your API key:
curl -o dental-check.html "https://storage.example.com/templates/demo-north-clinic/e21f9df7-d51c-4e6f-bf40-adb22b8096d0?versionId=67249fb34e849e724253a5c3a56fde59&X-Amz-Expires=3600&X-Amz-Signature=…"<p><strong>Reason for visit</strong></p><p>(Summarize the reason for the visit in one sentence.)</p><p><strong>Dental findings</strong></p><p>(List findings per tooth or quadrant. Use the modified Triadan system.)</p><p><strong>Plan</strong></p><p>(List only the treatments actually discussed.)</p>Bodies come back exactly as stored: HTML for note and meeting templates, the original JSON for structured templates. Links are valid for one hour (expiresAt). When currentVersionId is set, the link always returns that version, even if someone edits the template before you download it. If a link has expired, request the page again for fresh links.
6. Read retained versions
Vetnio keeps earlier versions of template bodies. Add /versions to any template endpoint to list them for one template, newest first:
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/data-export/templates/versions?templateId=e21f9df7-d51c-4e6f-bf40-adb22b8096d0" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"currentVersionId": "67249fb34e849e724253a5c3a56fde59",
"versions": [
{
"versionId": "67249fb34e849e724253a5c3a56fde59",
"isLatest": true,
"lastModified": "2026-10-04T16:25:59.000Z",
"size": 298,
"audit": {
"id": "c71da56c-3794-42b1-b411-6bfad145938f",
"occurredAt": "2026-10-04T16:25:59.325Z",
"actorName": "Alex Demo",
"actorType": "user",
"action": "template.content_updated",
"s3VersionId": "67249fb34e849e724253a5c3a56fde59"
}
},
{
"versionId": "67249fb48d5969a2bce62d9c129d1e2c",
"isLatest": false,
"lastModified": "2026-10-04T16:25:53.000Z",
"size": 184,
"audit": {
"id": "2eefff1c-df52-4cc3-b5fb-db62f6658666",
"occurredAt": "2026-10-04T16:25:53.988Z",
"actorName": "Alex Demo",
"actorType": "user",
"action": "template.content_updated",
"s3VersionId": "67249fb48d5969a2bce62d9c129d1e2c"
}
}
],
"nextCursor": null
}Then add /version with a versionId to read one version's exact body:
curl "https://vetnio.com/api/v2/workspaces/demo-north-clinic/data-export/templates/version?templateId=e21f9df7-d51c-4e6f-bf40-adb22b8096d0&versionId=67249fb48d5969a2bce62d9c129d1e2c" \
-H "Authorization: Bearer $VETNIO_API_KEY"{
"currentVersionId": "67249fb34e849e724253a5c3a56fde59",
"version": {
"versionId": "67249fb48d5969a2bce62d9c129d1e2c",
"isLatest": false,
"lastModified": "2026-10-04T16:25:53.000Z",
"size": 184,
"contentType": "text/html",
"audit": {
"id": "2eefff1c-df52-4cc3-b5fb-db62f6658666",
"occurredAt": "2026-10-04T16:25:53.988Z",
"actorName": "Alex Demo",
"actorType": "user",
"action": "template.content_updated",
"s3VersionId": "67249fb48d5969a2bce62d9c129d1e2c"
}
},
"content": "<p><strong>Reason for visit</strong></p><p>(Summarize the reason for the visit in one sentence.)</p><p><strong>Dental findings</strong></p><p>(List findings per tooth or quadrant.)</p>"
}Things to know about versions:
- Version lists return up to 50 entries per page; follow
nextCursoruntil it isnull. A page can be shorter, even empty, whilenextCursoris still set. versionIdandcursorvalues are opaque and can contain+,/and=. URL-encode them.auditsays who saved the version and how, when Vetnio has a matching audit entry. It is only filled for clinic note templates; otherwise it isnull.actorTypeisuser,vetnio_staff(Vetnio support acting on the clinic's request) orsystem.part=instructionslists or reads the versions ofinstructionsArtifactinstead of the body. It applies to note and meeting templates; structured and organization templates return400.- A version ID of the literal string
"null"belongs to a body saved before Vetnio kept versions. It can be overwritten;artifact.currentVersionIdshows it asnull. - Versions of deleted templates are not available: the endpoints return
404once the template is deleted.
Back up configuration incrementally
A nightly backup does not need to download everything every time. For each scope you back up:
- Settings and terms. Fetch the configuration export and compare it with the last saved copy, ignoring
exportedAt.termList.versionchanges whenever the term list is saved, so it is a quick change check. - Template inventory. Page through all four template endpoints. For each item, compare
artifact.currentVersionId(andinstructionsArtifact.currentVersionId) with what you stored. Download a body only when it changed or is new. WhencurrentVersionIdisnull, comparelastModifiedandsizeinstead. - Deleted templates. A template you stored that no longer appears after a complete pass was deleted in Vetnio. Keep your copy and mark it deleted; Vetnio no longer serves its versions.
- History between runs. If a template was edited several times since your last run, list its versions. They come newest first, so stop paging at the first
versionIdyou already have and fetch only the newer ones.
Run the steps for a scope one after another. The exports are read at request time and do not form one consistent snapshot, so a template edited during the run is picked up the next night.
Common errors
| Status | Message | Cause | Fix |
|---|---|---|---|
400 | Input validation failed with Unrecognized key: "limit" | A query parameter on GET /users/me/data-export/content. | Send no parameters to that endpoint. |
400 | This template kind has no separate instructions object. | part=instructions on a structured or organization template. | Use part=content. |
403 | This API key cannot access this endpoint | An organization or clinic key. | Use a personal key. |
403 | You are not an admin of this workspace | The user is a clinic member, not an admin. | Use an admin's key. |
403 | You are not a member of this organization, You need admin access to perform this action | Wrong organizationId, or not an organization admin. | Check the ID and the user's organization role. |
404 | Customer-owned template not found. | The template does not exist, was deleted, is a Vetnio default, or belongs to another clinic or organization. | Take templateId from the inventory of the same scope. |
404 | Retained template version not found. | The versionId does not exist for this template, or was not URL-encoded. | Take it from /versions and URL-encode it. |
500 | An unexpected error occurred | Storage could not be read, for example a damaged letterhead image. | Retry later; contact support if it persists. |
Complete script
This Python script backs up one clinic: its settings and terms, and every template category with bodies. It uses only the standard library.
import base64, json, os, pathlib, urllib.parse, urllib.request
BASE = "https://vetnio.com/api/v2"
KEY = os.environ["VETNIO_API_KEY"]
WORKSPACE_ID = "demo-north-clinic"
OUT = pathlib.Path("vetnio-backup") / WORKSPACE_ID
def get(path, **params):
query = urllib.parse.urlencode({k: v for k, v in params.items() if v is not None})
request = urllib.request.Request(f"{BASE}{path}?{query}", headers={"Authorization": f"Bearer {KEY}"})
with urllib.request.urlopen(request, timeout=660) as response:
return json.load(response)
def download(url, target):
with urllib.request.urlopen(url, timeout=300) as response:
target.write_bytes(response.read())
OUT.mkdir(parents=True, exist_ok=True)
content = get(f"/workspaces/{WORKSPACE_ID}/data-export/content")
letterhead = content["configuration"].pop("letterheadAsset")
(OUT / "configuration.json").write_text(json.dumps(content, indent=2))
if letterhead:
(OUT / "letterhead.png").write_bytes(base64.b64decode(letterhead["content"]))
for category in ["templates", "json-templates", "meeting-templates"]:
folder = OUT / category
folder.mkdir(exist_ok=True)
cursor = None
while True:
page = get(f"/workspaces/{WORKSPACE_ID}/data-export/{category}", limit=50, cursor=cursor)
for item in page["items"]:
for field, suffix in [("artifact", "body"), ("instructionsArtifact", "instructions.json")]:
artifact = item.get(field)
if artifact:
download(artifact.pop("contentUrl"), folder / f"{item['id']}.{suffix}")
(folder / f"{item['id']}.json").write_text(json.dumps(item, indent=2))
cursor = page["nextCursor"]
if cursor is None:
break
print(f"Backed up {WORKSPACE_ID} to {OUT}")Each page's links are used immediately, well within their one-hour lifetime. To add history, call the /versions and /version endpoints for each template as shown in step 6.
Next steps
- Export clinical data: consultations, transcripts, notes and recordings.
- Templates: how templates and structured templates shape the documents Vetnio writes.
- The Configuration export reference.
Endpoints used in this guide
- GET
/users/me/data-export/contentExport your settings and transcription terms - GET
/workspaces/{workspaceId}/data-export/contentExport a workspace's settings and transcription terms - GET
/organizations/{organizationId}/data-export/contentExport an organization's settings and transcription terms - GET
/workspaces/{workspaceId}/data-export/templatesExport a workspace's note templates - GET
/workspaces/{workspaceId}/data-export/json-templatesExport a workspace's structured (JSON) templates - GET
/workspaces/{workspaceId}/data-export/meeting-templatesExport a workspace's meeting templates - GET
/organizations/{organizationId}/data-export/templatesExport an organization's template blueprints - GET
/workspaces/{workspaceId}/data-export/templates/versionsList retained versions of a workspace note template - GET
/workspaces/{workspaceId}/data-export/templates/versionGet a retained version of a workspace note template - GET
/workspaces/{workspaceId}/data-export/json-templates/versionsList retained versions of a workspace JSON template - GET
/workspaces/{workspaceId}/data-export/json-templates/versionGet a retained version of a workspace JSON template - GET
/workspaces/{workspaceId}/data-export/meeting-templates/versionsList retained versions of a workspace meeting template - GET
/workspaces/{workspaceId}/data-export/meeting-templates/versionGet a retained version of a workspace meeting template - GET
/organizations/{organizationId}/data-export/templates/versionsList retained versions of an organization template - GET
/organizations/{organizationId}/data-export/templates/versionGet a retained version of an organization template
Last reviewed against the API on 2026-10-26.