Skip to main content
This guide takes you from an empty page to a working consultation. By the end you’ll have TORTUS embedded in your app, a consultation running, and structured results flowing back to your code.

Prerequisites

Before you begin, make sure you have:
  • A publishable key (pk_...) and a client ID + client secret from TORTUS. Contact us if you need them.
  • A modern browser target (ES2020+) and access to install from GitHub Packages.
  • A secure backend you control. Launch tokens must never be minted in the browser.

Steps

1

Install the SDK

Configure the @tortus-ai scope to use GitHub Packages, then install the package.
npm install @tortus-ai/embed-client
See Installation for the full registry and authentication setup.
2

Mint a launch token on your backend

The SDK authenticates with a short-lived launch token that you fetch from your own server, so your client secret never reaches the browser.
// server-side route, e.g. GET /api/tortus/client-secrets
const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");

const response = await fetch("https://api.tortus.ai/v1/oauth/launch", {
  method: "POST",
  headers: {
    Authorization: `Basic ${credentials}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    externalUserId: "your-internal-user-id",
    userPayload: { email: "clinician@example.com", firstName: "Ada", lastName: "Lovelace" },
  }),
});

const { launch_token } = await response.json();
// return { launchToken: launch_token } to your frontend
Read the full flow in Authentication.
3

Add a container to your page

TORTUS renders into an element you provide. Give it a width and height.
<div id="tortus-container" style="width: 100%; height: 600px;"></div>
4

Load TORTUS

Initialise the client. It starts in standby mode, waiting for instructions.
import { loadTortus } from "@tortus-ai/embed-client";

const client = await loadTortus({
  publishableKey: "pk_your_key_here",
  container: "#tortus-container",
  environment: "sandbox", // use "production" when you go live
  fetchClientSecrets: async () => {
    const res = await fetch("/api/tortus/client-secrets");
    const data = await res.json();
    return { launchToken: data.launchToken };
  },
});
5

Handle the result

Subscribe to consultation:completed and acknowledge receipt with finish().
client.on("consultation:completed", async ({ consultation, result, finish }) => {
  const { medicalNotes, letters, medicalCodes, transcriptions } = result.artifacts;

  // Filter by contentType, never rely on array order
  const note = medicalNotes.find((n) => n.contentType === "text/html");

  try {
    await saveToEhr({ reference: consultation.reference, note: note?.content, codes: medicalCodes });
    await finish({ status: "success" });
  } catch {
    await finish({ status: "failed" }); // lets the user retry in the TORTUS UI
  }
});
6

Start a consultation

Kick off a face-to-face consultation. TORTUS takes over the embedded view from here.
await client.consultations.start(
  {
    mode: "FACE_TO_FACE",
    patient: { name: "Jane Smith", dateOfBirth: "1985-03-15" },
    integration: { system: "EMIS" },
  },
  { returnTo: "home" },
);
That’s the full loop: load → start → receive results → acknowledge. Everything else builds on these steps.

Next steps

Consultations

Explore audio, face-to-face, and live recording modes plus EHR integrations.

Handling events & results

Learn the full event lifecycle and how to read artifacts.

Configuration

Every option loadTortus() accepts.

How it works

The mental model behind the embedded client.