Advanced

Client options, retries, timeouts, AbortSignal, custom fetch, and runtime notes.

new Medblocks(apiKey, options?) takes a second argument with knobs you can tune per process. Defaults are sensible for most apps. Only override when you have a reason.

Client Options

import { Medblocks } from "@medblocks/connect";

const mb = new Medblocks(process.env.MEDBLOCKS_API_KEY!, {
  baseUrl: "https://app.medblocks.com",
  apiVersion: "2026-04-25",
  timeout: 30_000,
  maxNetworkRetries: 3,
  fetch: globalThis.fetch,
});
OptionTypeDefaultPurpose
baseUrlstringhttps://app.medblocks.comOverride only for staging / a local mock.
apiVersionstring2026-04-25Sent as the Version header on every request. Pinned per SDK release.
timeoutnumber (ms)30_000Per-request timeout. Composes with caller-supplied AbortSignal.
maxNetworkRetriesnumber3Transient-failure retries. 0 disables retries.
fetchtypeof globalThis.fetchglobalThis.fetch.bind(globalThis)Injectable fetch. Useful for tests, mocking, or runtimes with a non-global fetch.

The defaults are exported as constants for tests and assertions:

import {
  DEFAULT_BASE_URL,
  DEFAULT_MAX_RETRIES,
  DEFAULT_TIMEOUT_MS,
  LATEST_API_VERSION,
} from "@medblocks/connect";

Retries

The SDK retries on:

  • Network errors (fetch rejected, abort caused by timeout).
  • HTTP 429. Honors the server’s Retry-After header.
  • HTTP 502, 503, 504.

It does not retry on 4xx other than 429, or on 500. Those surface as the appropriate MedblocksError subclass.

Backoff is exponential with jitter:

AttemptBackoff (ms)
0250 – 500
1500 – 750
21 000 – 1 250
32 000 – 2 250

Set maxNetworkRetries: 0 to disable retries entirely. Useful in integration tests against a mock server so failures surface immediately.

test/fixtures/medblocks.ts
const mb = new Medblocks("mb_sk_live_test", {
  baseUrl: fixtureUrl,
  maxNetworkRetries: 0,
});

AbortSignal

Every resource method takes an optional { signal } as its last argument. Pass an AbortSignal to cancel the request. Useful inside a route handler that’s already wired to the request’s abort signal.

server/routes/start-connect.ts
export async function startConnect(req: Request): Promise<Response> {
  const body = await req.json();

  const flow = await mb.patientFlow.init(
    {
      patient_id: body.patientId,
      return_url: body.returnUrl,
    },
    { signal: req.signal },
  );

  return Response.json({ url: flow.url });
}

The SDK composes your signal with its internal timeout signal. Whichever aborts first wins. A timeout abort surfaces as MedblocksApiError with code: "invalid_response" or as the thrown AbortError from fetch, depending on the runtime.

Custom Fetch

Override fetch to inject logging, tracing, or a per-request header.

server/medblocks-with-tracing.ts
import { Medblocks } from "@medblocks/connect";
import { trace } from "./tracing";

export const mb = new Medblocks(process.env.MEDBLOCKS_API_KEY!, {
  fetch: async (input, init) => {
    const span = trace.start("medblocks.fetch");
    try {
      return await globalThis.fetch(input, init);
    } finally {
      span.end();
    }
  },
});

The custom fetch is called for every request the SDK makes, including retry attempts. Do not throw from inside it; let fetch errors propagate.

Bundle Size

The browser-safe entry (just parseReturnUrl and the discriminated ReturnUrlResult type) is intentionally small. Importing only the helper, modern bundlers tree-shake out everything else:

import { parseReturnUrl } from "@medblocks/connect"; // tiny

Importing Medblocks in browser code pulls the full HTTP client and error hierarchy. Don’t. It exposes your secret key to end users.

Runtime Notes

RuntimeRequired versionNotes
Node.js≥ 20Global fetch is required.
Bun≥ 1.0Native.