Quickstart

Send a test patient to sign in at a sandbox hospital and print what they connected.

Medblocks lets a patient connect their own hospital records to your app. In this quickstart you’ll run a small server, send a test patient to sign in at a sandbox hospital, and print what they connected.

How it works

Three things happen.

  1. Your server starts the connection and redirects the patient to the URL Medblocks returns.
  2. The patient signs in to their hospital and approves access to their records.
  3. They come back to your app, and you read which hospitals they connected.

That is the whole flow. Let’s see how we can build it.

Install

npm install @medblocks/connect
pnpm add @medblocks/connect
yarn add @medblocks/connect
bun add @medblocks/connect

Add your API key

Your API key is a secret, so it lives only on your server. Put it in an environment variable. You can create one in your workspace.

.env
MEDBLOCKS_API_KEY="mb_sk_live_..."

Create the client

Create the client once and reuse it everywhere. It reads the key from the environment and fails fast if it is missing. This file is the same whichever server you use.

src/medblocks.ts
import { Medblocks } from "@medblocks/connect";

const apiKey = process.env.MEDBLOCKS_API_KEY;
if (!apiKey) throw new Error("MEDBLOCKS_API_KEY is not configured");

export const mb = new Medblocks(apiKey);

Start the connection

Add a route the patient opens to begin. It starts the connection and redirects the browser to the URL Medblocks returns. return_url is where the patient lands when they finish.

src/init-patient-session.ts
import { mb } from "./medblocks";

/**
 * GET /start — open a patient session and redirect the patient's browser to the
 * Medblocks-hosted page. No frontend: the redirect is the whole integration.
 */
export async function initPatientSession(_req: Request): Promise<Response> {
  const session = await mb.patientSession.init({
    patient_id: "demo-patient",
    return_url: "http://localhost:3000/connected",
    return_button_label: "Back to Acme Health",
  });

  return Response.redirect(session.url, 302);
}
src/init-patient-session.ts
import type { Request, Response } from "express";
import { mb } from "./medblocks";

/**
 * GET /start — open a patient session and redirect the patient to the
 * Medblocks-hosted page. No frontend: the redirect is the whole integration.
 */
export async function initPatientSession(_req: Request, res: Response) {
  const session = await mb.patientSession.init({
    patient_id: "demo-patient",
    return_url: "http://localhost:3000/connected",
    return_button_label: "Back to Acme Health",
  });

  res.redirect(session.url);
}

Read the connected facilities

When the patient finishes, they land on your return_url. Read who came back, look up the facilities they connected, and show them.

src/connections.ts
import { parseReturnUrl } from "@medblocks/connect";
import { mb } from "./medblocks";

/**
 * GET /connected — the return_url. The patient lands here after authorizing.
 * Read who returned, look up the sources they connected, and say so.
 */
export async function connected(req: Request): Promise<Response> {
  const result = parseReturnUrl(new URL(req.url).searchParams);
  if (!result) return new Response("Not a return URL", { status: 400 });

  const connections = await mb.patients.getConnections(result.patient_id, {
    hydrate: true,
  });
  const facilities = connections.map((c) => c.name).join(", ");

  return new Response(`Connected to ${facilities || "your records"} successfully`);
}
src/connections.ts
import type { Request, Response } from "express";
import { parseReturnUrl } from "@medblocks/connect";
import { mb } from "./medblocks";

/**
 * GET /connected — the return_url. Read who returned and which sources they connected.
 */
export async function connected(req: Request, res: Response) {
  const result = parseReturnUrl(new URL(req.url, "http://localhost:3000").searchParams);
  if (!result) {
    res.status(400).send("Not a return URL");
    return;
  }

  const connections = await mb.patients.getConnections(result.patient_id, {
    hydrate: true,
  });
  const facilities = connections.map((c) => c.name).join(", ");

  res.send(`Connected to ${facilities || "your records"} successfully`);
}

Run it

Put your two routes behind a server on port 3000.

src/server.ts
import { initPatientSession } from "./init-patient-session";
import { connected } from "./connections";

Bun.serve({
  port: 3000,
  routes: {
    "/start": { GET: initPatientSession },
    "/connected": { GET: connected },
  },
});

console.log("open http://localhost:3000/start");
src/server.ts
import express from "express";
import { initPatientSession } from "./init-patient-session";
import { connected } from "./connections";

const app = express();
app.get("/start", initPatientSession);
app.get("/connected", connected);

app.listen(3000, () => console.log("open http://localhost:3000/start"));

Then start it.

bun run src/server.ts

Using Node? Run node --env-file=.env --import tsx src/server.ts instead.

Connect the Epic sandbox

Open http://localhost:3000/start. Search for Epic Sandbox, sign in with the test credentials, and approve access.

That’s it

They return to your app, where the /connected route reads what they connected and shows it. That is a full patient connection, with no per-hospital code on your side.

What just happened

You just connected a patient to their hospital, end to end, without writing any hospital-specific login code.

  • Medblocks hosted the page where the patient picked their source. To build that screen in your own app, see your own UI.
  • The records keep arriving after the patient returns. Approving grants access. The data lands a little later through background pull.
  • For the full picture, the build guide walks through a complete integration, server and client.

See also