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.
| Key | Starts with | What it can do |
|---|---|---|
| Test | ovx_test_ | Push HTML, CSS, and JSON for any template. The clinic compares it before it replaces the report. It cannot publish. |
| Live | ovx_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.
- Sign in to the clinic. Every account finishes two-step sign-in before Settings opens.
- Open Settings and find SDK access.
- Create the test key. Copy it when it appears. It is shown once.
- 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. - 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 clinicconnect 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:
idandnamestatus:draft,published, orarchivedversion_idandversion_numberfor the current versionschema, includingsectionsand an optionalcode_layoutwithhtmlandcss
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.
| Method | Path | What it does |
|---|---|---|
| GET | /api/v1/sdk/workspace | Returns the clinic id and whether this key is test or live. |
| GET | /api/v1/sdk/templates | Lists 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}/publish | Publishes 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.
| What happened | Who | What the log says |
|---|---|---|
| A key was created or revoked | The owner or admin who did it | Created an SDK key, or Revoked an SDK key. The target includes test or live. |
| A template was saved or published through the API | System | Updated 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.”
| Status | When |
|---|---|
| 401 | The key is missing, malformed, unknown, or revoked. Message: “Invalid or revoked API key.” |
| 403 | A 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. |
| 404 | That template is not in this clinic. |
| 409 | A 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. |
| 422 | The schema is not valid. The message names what to finish before the save or publish can succeed. |