App Best Practices

Map to clinical interaction endpoints

Use clinical interactions to let users jump between Hint and your embedded experience.

Create a clinical interaction

Reference Create Partner Interaction. Interactions provide a durable pointer for the user to reopen your iframe later.

const createInteraction = async patientId => {
  const response = await fetch(
    `https://api.hint.com/v1/provider/patients/${patientId}/interactions`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        type: 'partner',
        status: 'draft'
      })
    }
  );

  return response.json();
};

Update a clinical interaction

Use Update Partner Interaction to update the interaction state (e.g., signed vs. draft) when your workflow completes.

const updateInteraction = async (patientId, interactionId, updates) => {
  const response = await fetch(
    `https://api.hint.com/v1/provider/patients/${patientId}/interactions/${interactionId}`,
    {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    }
  );

  return response.json();
};

Integrate with the Hint UI

Use the Hint Marketplace JS SDK to detect the current patient, respond to navigation changes, and close the iframe when your workflow ends. The SDK also exposes deep-link helpers (queryParams, fragment) so you can drive consistent navigation between Hint users.

Report your height on clinical surfaces

Clinical surfaces (clinical_interaction, clinical_chart) size the embed iframe only from your app's height reports. Include the Hint JS SDK on every embedded page — it reports height automatically via a ResizeObserver. Without it, your surface renders clipped to a ~150px strip inside the note window. This also applies to core_page surfaces with auto-adjust height disabled.

Using device capabilities (camera, microphone, geolocation)

Embedded surfaces run in a cross-origin iframe, so browsers block capabilities like navigator.mediaDevices.getUserMedia unless Hint delegates them to your app's origin. Delegation is opt-in per app: set browser_allow_list when updating your app (Update App) — for example {"app": {"browser_allow_list": ["camera", "microphone"]}}. Supported values are camera, microphone, and geolocation. Hint then renders your embed iframes with a matching Permissions Policy allow attribute.

  • The end user still sees the browser's standard permission prompt — the list delegates the capability, it does not grant permission.
  • The allow attribute is rendered when a surface is embedded, so changes to browser_allow_list only apply to newly opened surfaces — reload any already-open surface.
  • Without it, getUserMedia rejects immediately with NotAllowedError and no prompt is shown.
  • The handshake payload includes the current browser_allow_list, so your app can preflight before calling getUserMedia. On a NotAllowedError, check it first: if the capability is missing from the list, Hint hasn't delegated it (fix: the App Settings toggle); if it's present, the user denied the browser prompt (fix: the browser's site permissions). Both cases throw the same error, so this field is the only way to show the right message.
  • Current iOS honors the delegation (camera, microphone, and geolocation verified in iOS Safari). Older iOS versions may still block getUserMedia in cross-origin iframes, so a fallback such as <input type="file" accept="image/*" capture="environment"> is still worth providing.

Security and PHI handling

  • Treat the handshake access_token as a secret and scope it to the session (do not log it).
  • Verify X-Hint-Signature for the handshake payload using Webhooks Security.
  • Avoid storing or logging PHI unless you need it for the workflow. Prefer using IDs and fetching details on demand.

What’s Next

Did this page help you?