> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tortus.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Embed TORTUS and run your first consultation in a few minutes.

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](mailto:support@tortus.ai) 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

<Steps>
  <Step title="Install the SDK">
    Configure the `@tortus-ai` scope to use GitHub Packages, then install the package.

    ```bash theme={null}
    npm install @tortus-ai/embed-client
    ```

    See [Installation](/installation) for the full registry and authentication setup.
  </Step>

  <Step title="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.

    Save the `user_id` TORTUS returns and resend it as `userId` on later launches.

    ```ts theme={null}
    // server-side route, e.g. GET /api/tortus/client-secrets
    const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");

    // The TORTUS user ID you saved for this person on their first launch, if any.
    const savedUserId = await getTortusUserId(currentUser.id);

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

    const { launch_token, user_id } = await response.json();

    // First launch only: persist the ID so future launches resume this user.
    if (!savedUserId) {
      await saveTortusUserId(currentUser.id, user_id);
    }
    // return { launchToken: launch_token } to your frontend
    ```

    Read the full flow, including [persisting and resuming users](/authentication#persisting-and-resuming-users), in [Authentication](/authentication).
  </Step>

  <Step title="Add a container to your page">
    TORTUS renders into an element you provide. Give it a width and height.

    ```html theme={null}
    <div id="tortus-container" style="width: 100%; height: 600px;"></div>
    ```
  </Step>

  <Step title="Load TORTUS">
    Initialise the client. It starts in **standby mode**, waiting for instructions.

    ```ts theme={null}
    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 };
      },
    });
    ```
  </Step>

  <Step title="Handle the result">
    Subscribe to `consultation:completed` and acknowledge receipt with `finish()`.

    ```ts theme={null}
    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
      }
    });
    ```
  </Step>

  <Step title="Start a consultation">
    Kick off a face-to-face consultation. TORTUS takes over the embedded view from here.

    ```ts theme={null}
    await client.consultations.start(
      {
        mode: "FACE_TO_FACE",
        patient: { name: "Jane Smith", dateOfBirth: "1985-03-15" },
        integration: { system: "EMIS" },
      },
      { returnTo: "home" },
    );
    ```
  </Step>
</Steps>

<Check>
  That's the full loop: load → start → receive results → acknowledge. Everything else builds on
  these steps.
</Check>

## Next steps

<CardGroup cols={2}>
  <Card title="Consultations" icon="stethoscope" href="/guides/consultations">
    Explore audio, face-to-face, and live recording modes plus EHR integrations.
  </Card>

  <Card title="Handling events & results" icon="bell" href="/guides/events-and-results">
    Learn the full event lifecycle and how to read artifacts.
  </Card>

  <Card title="Configuration" icon="sliders" href="/configuration">
    Every option `loadTortus()` accepts.
  </Card>

  <Card title="How it works" icon="diagram-project" href="/concepts">
    The mental model behind the embedded client.
  </Card>
</CardGroup>
