Change report templates from your own code.

Each clinic has one test key and one live key. The key chooses the clinic. A push sends HTML, CSS, and JSON. The clinic compares it with the current report before either version is kept.

In the clinic app. Owners and admins create the test key and the live key in Settings.

Next: See what a template contains

What you are connecting

The API is a small set of HTTPS calls at https://api.orvexaai.cloud. The TypeScript SDK makes those same calls. It lives in this product as sdk/src/index.ts and is not published to npm, so any language can use the HTTP API directly.

You do not send a clinic id. The key belongs to one clinic and one environment, and every request uses that clinic. A browser login cannot call these routes, and an API key cannot open the clinic app.

Test key and live key

A clinic can have one active key of each kind. Creating a new one turns the previous key off immediately.

What each key is allowed to change
KeyStarts withWhat it can do
Testovx_test_Push HTML, CSS, and JSON for any template. The clinic compares it before it replaces the report. It cannot publish.
Liveovx_live_Push the same way, and publish a finished draft after the clinic has chosen a version.

Either key can push a template. The report on the website changes only after someone compares the two versions and chooses the pushed one. Use the live key when you also need to publish.

Create a key

Only an owner or admin can create or revoke keys.

  1. Sign in to the clinic. Every account finishes two-step sign-in before Settings opens.
  2. Open Settings and find SDK access.
  3. Create the test key. Copy it when it appears. It is shown once.
  4. Store it outside the repo, for example in an environment variable named ORVEXA_API_KEY. Do not commit it, paste it into chat, or put it in frontend code.
  5. Create the live key the same way when you are ready to update a published template.

Settings then shows the start of the key and the last time it was used. It does not show the secret again. Replace stops the old key immediately. Revoke does the same. Orvexa stores a hash of the key, not the key itself.

Connect

Import Orvexa from sdk/src/index.ts if you have the repository. Otherwise send the same request with any HTTP client.

import { Orvexa } from "./sdk/src/index.ts";

const apiKey = process.env.ORVEXA_API_KEY;
if (!apiKey) throw new Error("Set ORVEXA_API_KEY");

const orvexa = Orvexa.connect({
  apiUrl: "https://api.orvexaai.cloud",
  apiKey,
});

const workspace = await orvexa.workspace();
// workspace.environment is "test" or "live"
// workspace.organization_id is this clinic

connect rejects a key that does not start with ovx_test_ or ovx_live_. A revoked or unknown key fails on the first request with 401.

curl https://api.orvexaai.cloud/api/v1/sdk/workspace \
  -H "Authorization: Bearer $ORVEXA_API_KEY"
{
  "workspace": {
    "organization_id": "your-clinic-id",
    "environment": "test"
  }
}

You can send the key as Authorization: Bearer or as X-API-Key. Both name the same key.

Change a template

Read the template, then push its HTML, CSS, and JSON. The push does not replace the report. On the website, that template says “We noticed a change in the report.” Compare the current version with the pushed one and keep the one you want.pushCode sends the whole template. It does not merge a partial body.

const templates = await orvexa.templates();
const template = templates.find((item) => item.name === "Progress report");
if (!template) throw new Error("Template not found");

const result = await orvexa.pushCode(template.id, {
  html: "<article>{{ sections }}</article>",
  css: "article { font-family: Georgia, serif; }",
  json: template.schema,
});

if (result.pending) {
  // The clinic still has to compare the two versions and choose one.
}

Each template in the list includes:

  • id and name
  • status: draft, published, or archived
  • version_id and version_number for the current version
  • schema, including sections and an optional code_layout with html and css

A draft can be incomplete. A published template has to be complete, and so does a draft you publish. If the schema is not valid, the response says what to finish.

Open Report templates and choose Compare versions. Keeping the current version discards the push. Using the pushed version makes that HTML, CSS, and JSON the report. A live key cannot publish while a push is still waiting.

The layout's @page size is the paper size. A layout that does not set one is printed on US Letter. Custom layouts are drawn with Chromium so the CSS is applied. DM Sans and DM Serif Display are embedded when the layout names them.

A spider chart or donut is an empty element in the HTML. The report draws it. A script in the layout is removed and does not run.

<div data-orvexa-chart="radar" data-values="72,64,80" data-labels="Grip,VO2,HRV"></div>
<div data-orvexa-chart="donut" data-values="22,48,30" data-labels="Fat,Muscle,Water"></div>

data-values and data-labels are comma-separated. A value can be a field token the template already fills. A spider chart needs at least 3 numbers. A donut draws one slice per positive number and does not add a remainder.

HTTP API

Every path is under https://api.orvexaai.cloud. Send JSON, with Content-Type: application/json, on the write calls.

SDK routes. The clinic comes from the API key.
MethodPathWhat it does
GET/api/v1/sdk/workspaceReturns the clinic id and whether this key is test or live.
GET/api/v1/sdk/templatesLists the clinic's current templates.
GET/api/v1/sdk/templates/{id}Returns one template.
PUT/api/v1/sdk/templates/{id}Pushes HTML, CSS, and JSON for one template. The body is { "schema": { ... } }. The current report stays until the clinic compares the two versions.
POST/api/v1/sdk/templates/{id}/publishPublishes the current draft. Live key only. No body.

The TypeScript methods are workspace(), templates(), template(id), pushCode(id, { html, css, json }), save(id, schema), and publish(id).

What is recorded

Owners and admins can see this in two places. Settings shows the start of each active key and the last time it was used. Team, then Activity log, records the change itself.

How an SDK change appears in the activity log
What happenedWhoWhat the log says
A key was created or revokedThe owner or admin who did itCreated an SDK key, or Revoked an SDK key. The target includes test or live.
A template was saved or published through the APISystemUpdated a report template, or Published a report template. The target includes test or live.

The key is not a staff login, so a template write is recorded as System. The stored record keeps the environment, the template, and the version number. It does not keep the API key, patient information, or the template HTML.

In the activity log, choose Templates for saves, publishes, and restores. Choose SDK keys for keys that were created or revoked. All activity shows both.

Limits and errors

Limits are counted per key, over one minute.

  • Reads: 120
  • Saves: 60
  • Publishes: 30, and each publish also counts toward the save limit

A refused request returns 429 and a Retry-After header, with the message “Too many requests. Wait a moment and try again.”

Responses you should handle
StatusWhen
401The key is missing, malformed, unknown, or revoked. Message: “Invalid or revoked API key.”
403A test key tried to publish. Use the live key. Creating a key in Settings can also return 403 when the signed-in person is not an owner or admin, or when their session has not finished two-step sign-in.
404That template is not in this clinic.
409A push is still waiting to be compared, so publishing is refused. Or there is no draft to publish. Review the template on the website, then try again.
422The schema is not valid. The message names what to finish before the save or publish can succeed.