Skip to content

Browser SDK

The Browser SDK exposes window.BiomAPI with no dependencies. Use it to open the Web Widget, retrieve and share BiomPINs, or receive reports through URL fragments.

Each feature works independently. The widget provides BiomAPI’s upload and review interface. The SDK includes one narrow public REST helper for attributed BiomPIN retrieval, plus identity helpers and optional local history. It does not process files or manage API credentials.

Try the demo for widget import, sharing, and automatic fragment import, with one response viewer and a copyable integration example.

<script src="https://biomapi.com/static/js/biomapi-sdk.js"></script>

For version-pinned loading, use https://biomapi.com/static/v2.1.66/js/biomapi-sdk.js. The script’s origin determines the widget and default BiomAPI share destination. Loading it starts no requests, listeners, or storage access.

The examples use your application’s buttons and display callbacks. Where response appears, it is a successful StandardAPIResponse with a BiomPIN, returned by your REST request or the widget.

Use one stable, lowercase integration ID for the widget and retrieval helper:

const integrator = { id: 'example-ehr', name: 'Example EHR' };

name is required by the widget for display. Retrieval requires only id, but accepts the same object so one definition can be reused.

The biomapi.* ID namespace is reserved by convention for official BiomAPI clients. This naming convention does not authenticate a client; all integration IDs remain caller-declared operational attribution.

Open BiomAPI’s upload and review interface directly from a button click:

button.onclick = async () => {
try {
const response = await BiomAPI.widget.open({
integrator
});
if (response) displayResponse(response);
} catch (error) {
showError(error.message);
}
};

Send resolves to the reviewed StandardAPIResponse; Cancel or closing the popup resolves to null. See the Web Widget guide for options, errors, identity choices, and delivery security.

currentResponse is the response currently displayed in your application. Update it whenever a new report is shown. This example copies a BiomAPI link, including initials/ID when the checkbox is checked:

copyPinButton.onclick = () => BiomAPI.biompin.copyPin(currentResponse?.biompin?.pin).then(showCopyResult);
copyLinkButton.onclick = () => BiomAPI.biompin.copyUrl({
pin: currentResponse?.biompin?.pin,
context: includeIdentity.checked ? BiomAPI.context.fromResponse(currentResponse) : null
}).then(showCopyResult);

Omit targetUrl for a BiomAPI link. For an integrator link, supply your application’s fragment-enabled URL, such as https://calculator.example/import. Omit context to share without identity:

Destination Without identity With identity
BiomAPI /pin/{pin} /pin/{pin}#biomctx=...
Integrator /import#biompin={pin} /import#biompin={pin}&biomctx=...

Generated URLs are absolute. To build one without copying it, use BiomAPI.biompin.buildUrl({ pin, targetUrl, context }). Missing identifiers produce a link without context; sharing never searches history or saves an entry.

biompin.copyPin() and biompin.copyUrl() return Promise<boolean>: false means invalid input or clipboard failure. Display the outcome in your callback, such as showCopyResult.

Call copy helpers directly from a user gesture, before awaiting other work. They try the Clipboard API with a DOM-copy fallback. Disable PIN/link copying without a PIN and identity inclusion without identifiers. The demo checks Include initials/ID by default when identifiers are available; users can uncheck it to share without them. Reset the checkbox from each newly displayed response, never from history.

buildUrl() throws for invalid PINs, non-HTTP(S) destinations, URL credentials, existing BiomPIN/context query parameters, or incompatible anchors/hash-router fragments. Ordinary query parameters and unrelated key=value fragment fields are preserved. Existing BiomAPI fragment fields are replaced, so an anonymous link never retains stale context.

Use this in the application receiving integrator links. The SDK reads and removes #biompin and optional biomctx, then its retrieval helper can load the report with integration attribution. No widget opens and no history is saved automatically.

For one-time consumption:

const handoff = BiomAPI.fragments.consume();
// { pin: 'lunar-rocket-731904', context: { patientName: 'JD', patientId: '12345' } }
// Or null if no valid PIN was supplied; context itself can be null.

For automatic imports on page load and later fragment changes, register a listener. This example retrieves the report, restores missing identifiers locally, and prevents older requests from replacing a newer result:

let generation = 0;
const stopWatching = BiomAPI.fragments.watch(async ({ pin, context }) => {
const request = ++generation;
showLoading();
try {
// Only the PIN and integration attribution are sent. Context stays local.
const response = await BiomAPI.biompin.retrieve(pin, { integrator });
if (request !== generation) return;
displayResponse(BiomAPI.context.apply(pin, response, context));
} catch (error) {
if (request === generation) showError(error.message);
}
});
// Call stopWatching() when the component is disposed.

BiomAPI.biompin.retrieve(pin, { integrator, signal }) validates and normalizes the PIN and integration ID, calls the public BiomPIN retrieval endpoint at the origin from which the SDK was loaded, and returns a validated StandardAPIResponse. It rejects mismatched PIN responses.

The helper sends X-BiomAPI-Integrator-ID and, for HTTP(S) or extension pages, X-BiomAPI-Integrator-Origin derived from the calling page. The server retains only the origin’s host component. These properties are declared, spoofable analytics attribution and never authentication, authorization, billing, or quota signals. Cross-origin retrieval may require a CORS preflight because of the custom headers. BiomAPI advertises a one-week preflight cache duration; browsers may enforce a shorter limit.

Retrieval uses cache: 'no-store', omits cookies and referrer data, and never sends fragment identity context. It uses the public retrieval quota and does not accept an API key. Integrations requiring authenticated retrieval should call the REST endpoint directly and include the same integration headers.

HTTP and invalid-response failures reject with BiomAPI.biompin.BiomAPIRetrieveError, exposing status, requestId, and details. Invalid arguments throw TypeError; network and abort errors retain the browser’s native error type. Pass an AbortSignal as signal when the caller needs cancellation.

consume() reads only parameter-style fragments, not PINs in query strings or paths. It normalizes the PIN format and removes all biompin/biomctx fields using history.replaceState(), preserving unrelated fields, the query string, and existing navigation state. Cleanup happens before your callback, without navigation or an extra browser navigation entry.

Malformed/duplicate PINs return null. Malformed, duplicate, or unsupported-version context becomes null without blocking a valid PIN. Unrelated anchors and hash routes are left untouched. Retrieval failures do not restore the fragment: retain the handoff in your component if offering Retry, or reopen the link.

watch() handles the current fragment immediately and later hashchange events; its callback owns asynchronous error handling. It does not patch navigation APIs. After your own pushState() or replaceState(), call consume() explicitly because those APIs do not emit hashchange.

Identity context carries patient initials/name and ID separately from the retrieved report. Use fromResponse() when sharing and apply() after retrieval. These helpers never read history or send context to the server.

  • context.fromResponse(response): returns { patientName, patientId } or null.
  • context.encode(context): returns the base64url context string, or null when empty.
  • context.decode(encoded): returns { patientName, patientId } or null for malformed or unsupported context.
  • context.decodeFromLocation(location = window.location): reads context without modifying the URL.
  • context.apply(pin, response, context = null): fills missing patient name/ID from explicit context, returning a copy when identifiers change. It does not mutate the input, overwrite existing identifiers, or search history. Invalid PINs and responses with a different BiomPIN are left untouched.

The version-1 format is UTF-8 JSON encoded as base64url: { v: 1, patient_name, patient_id }. Only nonempty string identifiers are accepted. Context never changes clinical measurements, provenance, or API schemas.

Integrator links work without history. Add it when users need to find and reopen previously imported PINs in your application. The SDK provides the store and utilities; your code decides when to save and supplies the history UI.

This store is separate from BiomAPI’s history. Both are browser-local, not synced across browsers or devices. Saving a PIN does not extend its expiry or store the clinical response.

const store = BiomAPI.history.create({
storageKey: 'my-app:biomapi-history',
maxEntries: 250
});
try {
store.add({
pin: response.biompin.pin,
dbId: response.biompin.db_id,
expiresAt: response.biompin.expires_at,
// Optional: include identifiers only if your app chooses to retain them.
patientName: response.data.patient.name,
patientId: response.data.patient.id
});
} catch (error) {
showHistoryError(error.message);
}

Options default to storageKey: 'biomapi_history', maxEntries: 250, and the calling page’s localStorage. Use an app-specific key to keep stores separate. maxEntries must be a positive integer. Custom storage must implement getItem() and setItem().

Creating a store does not access storage. Reads and writes are synchronous and throw BiomAPI.history.HistoryStorageError with code STORAGE_READ_FAILED or STORAGE_WRITE_FAILED when they fail. Unreadable or incompatible data is not treated as an empty store and overwritten. Catch errors at your application’s history UI boundary; a failed save or delete must not be presented as successful. Invalid arguments throw TypeError or RangeError.

Method Behavior
add({ pin, dbId, expiresAt, patientName, patientId }) Adds or refreshes an entry, moves it to the front, deduplicates the PIN, enforces capacity, and returns the entry.
get(pin) Returns one entry or null.
list() Returns stored entries, newest first, without pruning.
search(query) Searches initials/name, patient ID, or PIN case-insensitively; an empty query returns all entries.
pruneExpired() Removes expired entries and returns the remaining entries.
pruneDbIdMismatch(dbId) Removes entries from other databases, including entries with no stored ID, and returns the remainder.
clearOne(pin) Removes one PIN and returns the remaining entries.
clearAll() Clears this store and returns an empty array.

Two stateless utilities accept entries, not PINs: BiomAPI.history.isExpired(entry) checks expiry, and BiomAPI.history.hasDbIdMismatch(entry, dbId) compares database IDs. A missing entry returns false; an entry with no stored database ID mismatches a known ID. Missing or unparseable expiry returns false, not a guarantee of retrievability. Use store.get(pin) when starting from a PIN.

const entries = store.list();
const matches = store.search('SYN-123');
const expired = BiomAPI.history.isExpired(store.get(pin));
// Your app obtains the current database ID through its own REST request.
store.pruneDbIdMismatch(currentDbId);
store.pruneExpired();

Bind deletion to separate user actions:

deleteButton.onclick = () => store.clearOne(selectedPin);
clearHistoryButton.onclick = () => store.clearAll();

Entries contain pin, patientName, patientId, expiresAt, dbId, createdAt, and updatedAt. PINs use the same validation and lowercase normalization as sharing and fragments. Expiry is an ISO timestamp; createdAt and updatedAt are Unix milliseconds for creation and the latest add(). Reads do not change timestamps. Returned entries are snapshots; call add() to update storage.

For updates, omitted fields retain their values; explicit null or an empty string clears them. A different dbId starts a fresh record for that PIN, without inheriting identity or expiry. Adding never removes other database entries except through the capacity limit; database cleanup is explicit through pruneDbIdMismatch(). These local checks do not verify a PIN with the server.

Local history is not encrypted. Retain only what your application needs, and treat stored PINs and identifiers as sensitive. Loading the SDK from BiomAPI does not give it access to BiomAPI’s history: storage belongs to the integrating page’s origin.

To restore missing identifiers from history, first look up the entry and check its database and expiry. Pass that entry as explicit context to BiomAPI.context.apply(pin, response, entry). The identity-context rules still apply. There is no automatic fallback from incoming context to history.

The legacy history SDK and window.BiomPinSDK remain available unchanged during migration. New integrations should load only biomapi-sdk.js; it includes the history store without depending on the old script.

Legacy usage Browser SDK equivalent
BiomPinSDK.history.create(options) BiomAPI.history.create(options) with a new storage key and the entry format above.
store.isExpired(entryOrPin), store.hasDbIdMismatch(entryOrPin, dbId) BiomAPI.history.isExpired(entry), BiomAPI.history.hasDbIdMismatch(entry, dbId); look up PINs with store.get(pin).
BiomPinSDK.context.encode(), decodeFromLocation() The corresponding BiomAPI.context helpers, using camelCase context fields.
BiomPinSDK.context.merge(pin, response, context, entries) Look up history explicitly if needed, then use the return value of BiomAPI.context.apply(pin, response, context). The response is no longer mutated.
BiomPinSDK.context.fromResponse(response) BiomAPI.context.fromResponse(response); returns { patientName, patientId } or null instead of the wire-format object.
BiomPinSDK.context.buildUrl(pin, context) BiomAPI.biompin.buildUrl({ pin, context }); returns an absolute BiomAPI URL.
BiomPinSDK.context.buildCalculatorUrl(targetUrl, pin, context) BiomAPI.biompin.buildUrl({ pin, targetUrl, context }); the target must consume #biompin, not the legacy query parameter.

Both SDKs can coexist, but must use separate storage keys. The new default biomapi_history does not read or change the legacy biompin_history. To retain old entries, explicitly map their fields into store.add() on the new store; nothing migrates automatically. Do not reuse a legacy key for the new entry format.

The version-1 encoded identity format is unchanged, but the new decoder validates context more strictly. Update context object shapes and link handling, and do not rely on legacy aliases or raw encoding helpers. History writes now report failures, and updates no longer prune other databases or treat null as an omitted value.

Action Signature Result
Open the hosted review interface open({ integrator: { id, name } }) `Promise<StandardAPIResponse
Identify widget failures BiomAPIWidgetError Error class with code
Inspect the messaging protocol protocolVersion Number
Action Signature Result
Retrieve with attribution retrieve(pin, { integrator, signal? }) Promise<StandardAPIResponse>
Build a BiomAPI or integrator link buildUrl({ pin, targetUrl?, context? }) Absolute URL string
Copy a PIN copyPin(pin) Promise<boolean>
Build and copy a link copyUrl({ pin, targetUrl?, context? }) Promise<boolean>
Identify retrieval failures BiomAPIRetrieveError Error class with status, requestId, and details
Action Signature Result
Consume the current handoff consume() { pin, context } or null
Consume now and on hashchange watch(callback) Stop-listening function
Action Signature Result
Read identifiers from a response fromResponse(response) { patientName, patientId } or null
Encode context encode(context) Base64url string or null
Decode context decode(encoded) Context object or null
Read context without changing the URL decodeFromLocation(location?) Context object or null
Restore missing identifiers locally apply(pin, response, context?) Original or copied response
Action Signature Result
Create a local store create({ storage?, storageKey?, maxEntries? }) History store
Check one entry’s expiry isExpired(entry) Boolean
Compare one entry’s database hasDbIdMismatch(entry, dbId) Boolean
Identify storage failures HistoryStorageError Error class with code

History stores expose add, get, list, search, pruneExpired, pruneDbIdMismatch, clearOne, and clearAll, described in Manage entries.