Page cover

Iframe Integration Guide

This document provides comprehensive instructions for embedding the RADPAIR application within your own application as an iframe.

🎉 Welcome to Our Documentation 🎉


You can reference the high-level workflow of the process below as you go over the rest of the document:

Initial Configuration

Before integrating RADPAIR, a few preliminary steps are necessary to set up your environment and user permissions correctly.

Organization Setup

  • Organization Creation: Initially, RADPAIR will establish an organization specifically for your team.

  • User Registration: You will need to sign up with RADPAIR as a member of this organization. A unique organization code will be provided to you for this purpose.

  • Admin Assignment: Once your account is verified, RADPAIR will grant you admin privileges within your organization.

Authentication

To facilitate a secure environment, RADPAIR utilizes a straightforward authentication workflow. By doing so, admins can manage user access securely and efficiently.

API Key-based Authentication

RADPAIR is migrating to a more secure and flexible API Key-based authentication system. We strongly recommend transitioning from admin credential-based authentication to API keys, as this approach simplifies integration and provides better security controls for your application.

Benefits of API Key Authentication

  • Enhanced Security: No need to share admin credentials across systems

  • Simplified Integration: Streamlined authentication flow

  • Fine-grained Access Control: API keys can be scoped to specific organizations

Obtaining an API Key

You can create an API key from your org admin's account:

  1. Navigate to the organization's page

  2. Select the organization you wish to create the API key for

  3. Click on the options button for the org (⋮) and click on the "API Keys" option

  4. Click "Create New API Key"

  5. Copy and securely store the generated API key - it will only be shown once

Note: API keys should be treated as sensitive credentials and stored securely. Never share or commit API keys to version control.

Security Best Practices

  1. Store API Keys Securely: Never expose your API key in client-side code or public repositories

  2. Use HTTPS: Always make API requests over HTTPS

  3. Implement Token Rotation: Periodically generate new tokens for long-lived sessions

  4. Revoke Unused Tokens: Revoke tokens when they're no longer needed

This API Key authentication method provides a more secure and flexible way to integrate with RADPAIR while maintaining full control over user access and report management.

Creating a Token

Endpoint

  • URL: https://api.radpair.com/integrations/auth/token

  • Method: POST

Request Body

{
  "user_email": "[email protected]",
  "first_name": "John",
  "last_name": "Doe",
  "user_role": "attending_radiologist",
  "org_path": ["Clinic West", "Radiology"],
  "auto_create_suborgs": true
}
Parameter
Type
Required
Default
Description

user_email

string

Email of the user

first_name

string

User's first name

last_name

string

User's last name

user_role

string

attending_radiologist

org_path

array

Path to sub-organization

auto_create_suborgs

boolean

Auto-create sub-orgs if they don't exist

Organization Management

The API Key system supports hierarchical organization structures. You can specify an organization path when creating users or reports to target specific sub-organizations:

{
  "user_email": "[email protected]",
  "first_name": "John",
  "last_name": "Doe",
  "org_path": ["West Coast", "San Francisco", "Radiology"]
}

If the auto_create_suborgs flag is set to true, any missing organizations in the path will be automatically created. Otherwise, the API will return an error if the specified organization doesn't exist.

Response

Success (200)

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Error Responses

  • 400: Bad Request - Invalid request format or parameters.

  • 401: Unauthorized - Invalid API key.

  • 500: Internal Server Error.

    Example request:

fetch("https://api.radpair.com/integrations/auth/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer your-api-key-here",
  },
  body: JSON.stringify({
    user_email: "[email protected]",
    first_name: "John",
    last_name: "Doe",
    org_path: ["Clinic West", "Radiology"],
  }),
})
  .then((response) => response.json())
  .then((data) => {
    const accessToken = data.access_token;
    // Use this token for iframe authentication
  });

Revoking a Token

Endpoint

  • URL: https://api.radpair.com/integrations/auth/token/revoke

  • Method: POST

Request Body

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Parameter
Type
Required
Description

access_token

string

JWT access token to revoke

Response

Success (200)

{
  "message": "Token revoked"
}

Error Responses

  • 400: Bad Request - Invalid request format or parameters.

  • 401: Unauthorized - Invalid API key.

  • 500: Internal Server Error.

Using the Access Token with the iframe

Once you've obtained an access token you can use it with the iframe:

iframe.postMessage({ authentication: `Bearer ${accessToken}` }, RADPAIR_URL);

Token Expiration

  • RADPAIR access tokens expire after 24 hours.


Iframe

Embedding the iframe

Embed the within your application by adding the following component:

<iframe
  allow="microphone; hid"
  src={"<RADPAIR_URL>"}
  style={{ width: "100%", height: "600px" }}
/>

A few notes:

  1. The RADPAIR_URL is https://external.radpair.com

  2. The allow attribute needs both permissions:

    • microphone: Required for dictation through RADPAIR

    • 🎉 Recent update🎉 hid: Required for accessing HID (Human Interface Device) devices like dictation hardware (e.g., SpeechMike)

  3. The width and height can be customized based on how RADPAIR will fit within your application


Optional: Credentialless mode (experimental)

When multiple RADPAIR iframe instances are open (e.g., one inside your integration and another in a separate browser tab), browser storage and tokens can conflict. For example:

  • A user logs into RADPAIR in one tab as User A.

  • In a second tab or integration, they try to log in as User B.

  • Because tokens/cookies are shared across iframes by default, the session from User A is reused. This can cause confusion and prevent correct access to reports tied to the intended user.

To avoid this, you can enable credentialless mode. This isolates each iframe in its own isolated context, so tokens and storage are not shared between instances.

<iframe
  allow="microphone; hid"
  credentialless
  src={"<RADPAIR_URL>"}
  style={{ width: "100%", height: "600px" }}
/>

Iframe interactions

We support interactions with the iframe through messages (postMessage). See the below for a comprehensive list of all the interactions we support:

  1. Authentication: You can send a request to authenticate the user by passing the previously acquired access_token to the iframe using:

    iframe.postMessage({ authentication: 'Bearer <ACCESS_TOKEN>' }, <RADPAIR_URL>);
  2. Headless Mode: To enable a 'headless' version of the app, which hides the sidebar, appbar, and other components that are may not be necessary when displayed in an iframe, you can do that as follows:

    iframe.postMessage({ headless: <true|false> });

    You can also enable the headless by default by appending a query parameter to the RADPAIR URL:

    https://external.radpair.com/?headless=true
  3. Opening a RADPAIR report: To update the report RADPAIR has open:

    iframe.postMessage({ report_id: "<REPORT_ID>" });

    If a report_id of null is sent it closes the report. For more on the report_id, see the next section.

  4. Logging Out: To trigger a logout from the embedded iframe:

    iframe.postMessage({ logout: true });

Further Iframe Interactions during Reporting

We support further fine-grained interactions with the iframe during reporting, such as stopping and starting the recording (dictation), processing a transcript, signing a report, and so on. These can be useful if you plan on mapping controls of devices like a SpeechMike to RADPAIR events. Find the list of actions we support below.

  1. Starting or stopping the recorder:

     iframe.postMessage({ report_action: 'start_recording|stop_recording' }, <RADPAIR_URL>);

    You can also target a specific field when interacting with the recorder:

     iframe.postMessage({ report_action: 'start_recording_transcript|stop_recording_transcript' }, <RADPAIR_URL>);

    And:

     iframe.postMessage({ report_action: 'start_recording_final_report|stop_recording_final_report' }, <RADPAIR_URL>);
  2. Processing a report:

     iframe.postMessage({ report_action: 'process_report' }, <RADPAIR_URL>);
  3. Signing a report:

     iframe.postMessage({ report_action: 'sign_report' }, <RADPAIR_URL>);

    When multiple sign options are available (e.g., "sign prelim" and "sign final"), this action will automatically select the primary sign type. For example, if both options are available, the system will default to "sign final" as the primary type.

    After successful signing, the system will automatically send the signed report data back to the parent window with the following payload:

    {
        "final_report_signed": {
            "signType": "[PRIMARY_SIGN_TYPE_USED]",
            "html_final_report": "<HTML_FINAL_REPORT>",
            "final_report": "<FINAL_REPORT>"
        }
    }
  4. Field Reporting: If you have fields (e.g. [Placeholder]) in your template (in the final report box), these can be navigated via these actions:

     iframe.postMessage({ report_action: 'next_final_report_field|prev_final_report_field' }, <RADPAIR_URL>);
  5. Receiving Signed Report Event: You can send the finalized report data back to the parent window using the following command:

     iframe.postMessage({ report_action: 'send_report_to_parent_window' }, <RADPAIR_URL>);

    The parent window will receive the following payload:

    {
        "final_report_signed": {
            "signType": "manually_triggered",
            "html_final_report": "<HTML_FINAL_REPORT>",
            "final_report": "<FINAL_REPORT>"
        }
    }
  6. Creating Impressions:

    iframe.postMessage({ report_action: 'create_impression' }, <RADPAIR_URL>);

    Triggers the creation of impressions in the report based on the current content.

  7. Adding an Addendum:

    iframe.postMessage({ report_action: 'add_addendum' }, <RADPAIR_URL>);

    Appends an addendum section to the existing report (This will be added only to the final report box).

Addendum Added to Final Report
  1. Hiding Multi-Author UI Elements:

    iframe.postMessage({
      hide_multi_author_actions: {
        signButton: true,
        actionsButton: true,
        addAddendumButton: true,
        completeDiscardButton: false,
    
      }
    }, <RADPAIR_URL>);

Controls the visibility of specific UI elements in multi-author scenarios. Set individual properties to true to hide the corresponding buttons, or false to show them.

What does completeDiscardButton do?: This button allows users to fully discard all changes in a report, restoring it back to its original state, and automatically unlocks and unassigns the report from the current user. This is different from regular discard which only reverts recent changes - complete discard performs a full restoration and releases the report entirely.

  1. Discard and Close Report:

iframe.postMessage({ report_action: 'discard_and_close_report' }, <RADPAIR_URL>);

Discards any unsaved changes in the current report and closes it, returning to the previous screen.

  1. Complete Discard and Close Report:

iframe.postMessage({ report_action: 'complete_discard_and_close_report' }, <RADPAIR_URL>);

Completely discards and unassigns the entire report (restoring it back to original state) and closes it, returning to the previous screen.

11. Save and Close Report:

iframe.postMessage({ report_action: 'save_and_close_report' }, <RADPAIR_URL>);

Saves the current state of the report and closes it, returning to the previous screen.

12. Save Report:

iframe.postMessage({ report_action: 'save_report' }, <RADPAIR_URL>);

Saves the current state of the report but does not close it.

13. Unlock Report:

iframe.postMessage({ report_action: 'unlock_report' }, <RADPAIR_URL>);

Unlocks a report that has been previously signed or locked, allowing it to be edited again.

14. Configure Toast Notifications:

iframe.postMessage({ 
    configure_toasts: { 
      success: { enabled: false },
      // info, warning, and error are also supported
    } 
  }, '*');

Configures the visibility of toast notifications by type. Set enabled to false to disable a specific type of toast notification, or true to enable it. Supported toast types are success, info, warning, and error.

Events from the RADPAIR Iframe

RADPAIR sends events to the parent window to notify it of various actions and state changes. These events can be used to track user interactions and update your application's UI accordingly.

🎉 Recent update🎉 Listening for events can also be an alternative to webhooks:

As an alternative to subscribing to webhooks or socket events, RADPAIR supports real-time reporting event delivery via postMessage events emitted from the iframe. These are particularly useful for integrations that want to avoid server-side webhook complexity or need immediate client-side awareness of report actions like signing, saving, or discarding.

To receive events from the RADPAIR iframe, add an event listener to your parent window:

window.addEventListener('message', function(event) {
  // Verify the origin for security
  if (event.origin !== "<RADPAIR_URL>") return;
  
  // Check if this is a reporting event
  if (event.data && event.data.type === "reporting_event") {
    const reportingEvent = event.data.event;
    const payload = event.data.payload;
    
    console.log(`Received reporting event: ${reportingEvent}`, payload);
    
    // Handle different event types
    switch (reportingEvent) {
      case "report_opened":
        // Handle report opened event
        break;
      case "transcript_focused":
        // Handle transcript focused event
        break;
      // Handle other events...
    }
  }
});

Base payload fields (always included)

{
  "type": "reporting_event",
  "event": "report.signed",
  "payload": {
    "timestamp": 1743518340903,
    "user_info": { "id": "user_1", "email": "[email protected]", "full_name": "Jane Doe", "role": "radiologist" },
    "report_id": "12345",
    "report_info": {
      "report_id": "12345",
      "report_label": "XR Chest",
      "report_status": "drafting",
      "is_drafting": true,
      "metadata": {},
      "linked_reports": [],
      "accession_number": "ACC-001",
      "mrn": "MRN-001",
      "order_id": "ORD-001",
      "site_id": "SITE-001",
      "assigning_authority": "HOSP",
      "native_id": "NATIVE-001"
    }
  }
}

Available Events

RADPAIR sends the following events to the parent window:

  1. Report Lifecycle Events:

{
"type": "reporting_event",
"event": "report_opened",
"payload": {
 "report_id": "12345",
 "timestamp": 1743518340903
}
}
{
  "type": "reporting_event",
  "event": "report_closed",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report.signed",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "user_info": {
      "id": "user_123",
      "email": "[email protected]",
      "full_name": "Dr. John Smith",
      "role": "attending_radiologist"
    },
    "report_info": {
      "report_id": "12345",
      "report_label": "XR Chest",
      "report_status": "signed",
      "is_drafting": false,
      "metadata": {},
      "linked_reports": [],
      "accession_number": "ACC-001",
      "mrn": "MRN-001",
      "order_id": "ORD-001",
      "site_id": "SITE-001",
      "assigning_authority": "HOSP",
      "native_id": "NATIVE-001"
    },
    "sign_type": "sign",
    "html_final_report": "<HTML_FINAL_REPORT>",
    "final_report": "<FINAL_REPORT>"
  }
}
{
  "type": "reporting_event",
  "event": "report_saved",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report_unlocked",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report_discarded",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report.discarded_completely",
  "payload": {
   "report_id": "12345", "timestamp": 1743518340903 
   }
}
{
  "type": "reporting_event",
  "event": "report_discarded_and_closed",
  "payload": {
    "final_report": "This report was discarded.",
    "html_final_report": "<p>This report was discarded.</p>"
  }
}
{
  "type": "reporting_event",
  "event": "report_updated",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "final_report": "Updated content.",
    "html_final_report": "<p>Updated content.</p>"
  }
}
{
  "type": "reporting_event",
  "event": "report_processed",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "final_report": "Processed text.",
    "html_final_report": "<p>Processed text.</p>"
  }
}
{
  "type": "reporting_event",
  "event": "report_impressions_processed",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report_dictated",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "report_saved_and_closed",
  "payload": {
    "final_report": "Patient has pneumonia.",
    "html_final_report": "<p>Patient has pneumonia.</p>"
  }
}
{
  "type": "reporting_event",
  "event": "final_report_updated",
  "payload": {
    "final_report": "Updated content.",
    "html_final_report": "<p>Updated content.</p>"
  }
}
{
  "type": "reporting_event",
  "event": "report.linked",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "linked_reports": [
      {
        "report_id": "67890",
        "accession_number": "ACC002",
        "mrn": "MRN123"
      }
    ]
  }
}
{
  "type": "reporting_event",
  "event": "report.unlinked",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "unlinked_reports": [
      {
        "report_id": "67890",
        "accession_number": "ACC002",
        "mrn": "MRN123"
      }
    ]
  }
}

The two new events (report.linked and report.unlinked) are sent when users link or unlink reports using the report linking feature in the RADPAIR UI or via the API. These events notify the parent window/iframe about changes to report groupings, including which specific reports were linked or unlinked via their identifiers (report_id, accession_number, MRN, etc.).

  1. Editor Focus Events:

{
  "type": "reporting_event",
  "event": "transcript_focused",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340893
  }
}
{
  "type": "reporting_event",
  "event": "transcript_blurred",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340893
  }
}
{
  "type": "reporting_event",
  "event": "final_report_focused",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
{
  "type": "reporting_event",
  "event": "final_report_blurred",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903
  }
}
  1. Multi Author (Reject):

{
  "type": "reporting_event",
  "event": "report.changes_rejected",
  "payload": {
    "report_id": "12345",
    "timestamp": 1743518340903,
    "user_info": {
      "id": "user_123",
      "email": "[email protected]",
      "full_name": "Dr. Jane Reviewer",
      "role": "attending_radiologist"
    },
    "report_info": {
      "report_id": "12345",
      "report_label": "XR Chest",
      "report_status": "unread",
      "is_drafting": false,
      "metadata": {},
      "linked_reports": [],
      "accession_number": "ACC-001",
      "mrn": "MRN-001",
      "order_id": "ORD-001",
      "site_id": "SITE-001",
      "assigning_authority": "HOSP",
      "native_id": "NATIVE-001"
    },
    "new_status": "unread",
    "previous_status": "pending_approval",
    "new_owner_details": {
      "id": "user_456",
      "email": "[email protected]",
      "full_name": "Dr. Sarah Resident",
      "role": "resident"
    },
    "previous_owner_details": {
      "id": "user_123",
      "email": "[email protected]",
      "full_name": "Dr. Jane Reviewer",
      "role": "attending_radiologist"
    }
  }
}

When using multi-author workflows, reviewers (typically attending radiologists) can reject changes made to a report and return it to the previous owner for revisions. This triggers a specific event that includes ownership transfer details and status changes.

When it's triggered:

  • A reviewer rejects changes made to a report

  • The report is automatically transferred back to the previous owner

Use Cases

These events can be used for various purposes:

  1. UI Updates: Update your application's UI based on which editor is currently focused

  2. Tracking: Monitor user interactions with the report for analytics or auditing

  3. Integration with External Devices: Synchronize external devices (like dictation hardware) with the current state of the RADPAIR interface

  4. Workflow Automation: Trigger automated actions when reports are opened, closed, or signed

Theme Customization

The app's appearance can be customized through a theme configuration message. The theme system handles certain properties specially while allowing direct palette customization for others.

Send a theme configuration message to customize the app's appearance:

window.postMessage({
  theme: {
    // Properties with special handling
    recordButtonColor: "#212132",  // Maps to record.main
    diffCheckColor: "#9894f9",     // Direct palette property
    fontFamilyName: "inter",       // Font configuration
    logoWideUrl: "/logo.png",      // Full logo for regular display
    logoIconUrl: "/mini_logo.png", // Square logo for small screens

    // Direct palette properties
    background: {
      default: "#212132",    // Main app background
      paper: "#1E1E2E",      // Cards/surfaces background
      medium: "#1A1A28",     // Medium shade for layering
      dark: "#181829",       // Darker shade for depth
      extraDark: "#181829"   // Maximum contrast areas
    },
    primary: {
      main: "#9894f9",       // Primary brand color
      dark: "#09144f",       // Hover states
      light: "#c4ccff"       // Highlights
    },
    secondary: {
      main: "#3B967D"        // Some input box strokes/borders
    },
    text: {
      primary: "#ffffff",    // Main text color
      secondary: "#999999"   // Secondary text color
    },
    error: {
      main: "#fff",          // Main error color
      light: "#ff3333",      // Warning variant
      dark: "#cc0000",       // Critical variant
      extraLight: "#ff6666"  // Error backgrounds
    },
    success: {
      main: "#31C48D"        // Checkmark icons
    },
    alert: {
      info: "#9894f9"        // Info alert color (maps to info.main)
    },
    divider: "#373745"       // Dividing lines color
  }
}, "*")

Special Handling Properties

These properties receive special treatment in the theme system:

  • recordButtonColor: Maps to record.main in the palette

  • diffCheckColor: Direct palette property for diff highlighting

  • fontFamilyName: Configures the application font

  • logoWideUrl: Full logo for regular display

  • logoIconUrl: Square/icon logo for small screens

Direct Palette Properties

These properties are applied directly to the theme palette:

Background Colors

  • background.default: Main application background

  • background.paper: Cards and surfaces

  • background.medium: Layering elements

  • background.dark: Depth elements

  • background.extraDark: Maximum contrast areas

Brand Colors

  • primary.main: Primary brand color

  • primary.dark: Hover states

  • primary.light: Highlights

UI Element Colors

  • secondary.main: Controls input box strokes and borders

  • success.main: Used for checkmark icons

Text Colors

  • text.primary: Main text color

  • text.secondary: Secondary text color

Status Colors

  • error.main: Main error color

  • error.light: Warning variant

  • error.dark: Critical variant

  • error.extraLight: Error backgrounds

Component Colors

  • alert.info: Info alert color (automatically maps to info.main)

  • divider: Dividing lines

Notes

  • All color values should be provided in hexadecimal format (e.g., #FF0000 for red)

  • Both logo URLs should be provided together for proper responsive behavior

  • The alert.info color is automatically mapped to info.main in the palette

  • Font configuration requires a valid font family name that is available in the application

Application Usage

Integrating RADPAIR's functionalities involves creating a report via REST API and receiving events via webhooks.

Workflow to initialize the iframe

Once you have established the webhook connection and have the iframe embedded as in the steps shown above, you would follow the workflow below:

  1. Embed the iframe as above

  2. Establish the webhook endpoint

  3. Register your webhook

  4. Add a listener callback to receive messages from the RADPAIR iframe event. The RADPAIR iframe sends events to the parent component in two different instances: when the app is ready to receive messages (as the app may take a short amount of time to start), and when the app successfully signs in (using the access token obtained from earlier). Below, you'll find JavaScript code defining the types of events, and how to set the listener.

    const IFRAME_PARENT_EVENT_TYPES = {
      SIGN_IN_SUCCESSFUL: "sign_in_successful",
      APP_READY: "app_ready",
    };
    
    const receiveMessage = (message) => {
      const event = message.data?.event;
      switch (event) {
        case IFRAME_PARENT_EVENT_TYPES.APP_READY:
          // RADPAIR is now ready to receive events
          break;
        case IFRAME_PARENT_EVENT_TYPES.SIGN_IN_SUCCESSFUL:
          // RADPAIR has now authenticated the user
          break;
        default:
          console.log("Unknown event received from iframe:", event);
      }
    };
    
    window.addEventListener("message", receiveMessage);
  5. Await the IFRAME_PARENT_EVENT_TYPES.APP_READY event.

  6. Upon receiving the event above, send in the Authentication request

  7. Await the IFRAME_PARENT_EVENT_TYPES.SIGN_IN_SUCCESScFUL event.

  8. RADPAIR is now authenticated and can receive other events like report_id, theme etc., as above.

  9. We will assume you have a database model for saving your reports in your own database. You will need to add a field to your schema to associate your own report ID with a RADPAIR report ID. Therefore, you will need to add a field such as radpair_report_id. This is essential for the next step.

  10. When a user needs to start a new report on your app, you will follow the pre-caching workflow as follows:

    1. Create the Report Ahead of Time Use the POST /integrations/reports/create endpoint with all required metadata fields. The report will be saved with a status of unread.

    2. Find the Report When User Is Ready Just before the user needs to open the report (e.g., after clicking on it), use the /integrations/reports/find endpoint to retrieve the report_id.

    3. Open the Report in the Iframe Pass the report_id into the embedded RADPAIR iframe:

      iframe.postMessage({ report_id: "<REPORT_ID_FROM_FIND>" }, RADPAIR_URL);

      The report will open instantly, and the user will be assigned as the owner automatically since the report is still in unread status.

    4. Fallback (only if no report_id): POST /integrations/reports/create

  11. When the user is done dictation, the user can click on the "Process Transcript" button.

  12. After the report is processed, the user can make any final changes to the report before signing or saving the report.

  13. After the user signs or saves the report a webhook event will be sent. See webhooks section below for more details.

Creating Reports with Pre-Caching

RADPAIR allows partners to pre-create ("pre-cache") reports in advance of user interaction to reduce perceived latency and improve user experience. Rather than creating the report at the moment a user clicks to open it, which may involve time-consuming metadata processing, the system supports creating reports ahead of time, storing them in an "unread" state.

Why Pre-Caching Matters

Creating reports in real time can take varying amounts of time depending on system load and metadata complexity. By pre-caching, all of that work is already completed by the time the user interacts with the report, resulting in an immediate load and a smoother experience.

Full Pre-Caching Workflow

  1. Create the Report Ahead of Time Use the POST /integrations/reports/create endpoint with all required metadata fields. The report will be saved with a status of unread.

Endpoint: POST https://api.radpair.com/integrations/reports/create

{
  "accession_number": "ACC12345",
  "metadata": {
    "studyDescription": "Chest X-ray",
    "clinical_notes": "Shortness of breath",
    "laterality": "bilateral",
    "views": "2",
    "comparison": "None",
    "symptom": "Dyspnea",
    "patient_age": "42",
    "patient_gender": "M",
    "pre_findings": "", // DIACOM SR DATA goes here
  },
  "metadata_source": "yourIntegrationSystem",
  "org_path": ["Your Clinic", "Radiology"]
}
  1. Find the Report When User Is Ready Just before the user needs to open the report (e.g., after clicking on it), use the /integrations/reports/find endpoint to retrieve the report_id.

Endpoint: POST https://api.radpair.com/integrations/reports/find

{
  "accession_number": "ACC12345",
  // Any other identifier used when report was created, e.g. mrn, native_id, etc
  "org_path": ["Your Clinic", "Radiology"]
}
  1. Open the Report in the Iframe Pass the report_id into the embedded RADPAIR iframe:

    iframe.postMessage({ report_id: "<REPORT_ID_FROM_FIND>" }, RADPAIR_URL);

    The report will open instantly, and the user will be assigned as the owner automatically since the report is still in unread status.

Summary

Pre-caching allows you to:

  • Eliminate slow load times for report creation

  • Ensure users can interact with reports instantly

  • Maintain full control over report lifecycle and ownership


Ownership Behavior

  • Unread Status: The first user to open the report becomes the owner.

  • Assigned Reports: If a report already has an owner or is not in unread status, use the transfer-ownership API to assign it.

Endpoints

Creating & Updating Reports

This endpoint serves as an upsert function. It will create a new report if one doesn't exist with the provided identifiers or update an existing one if the metadata payload changes.

Endpoint: POST https://api.radpair.com/integrations/reports/create

Request Body

{
  "accession_number": "string",
  "metadata": {
    "studyDescription": "string",
    "clinical_notes": "string",
    "laterality": "string",
    "views": "string",
    "comparison": "string",
    "symptom": "string",
    "modality": "string",
    "contrast": "string",
    "patient_age": "string",
    "patient_gender": "string",
    "pre_findings": "", // DIACOM SR DATA goes here
  },
  "metadata_source": "string",
  "native_id": "string",
  "assigning_authority": "string",
  "order_id": "string",
  "site_id": "string",
  "mrn": "string",
  "org_path": ["Clinic A", "Department B"],
  "auto_create_suborgs": true,
  "process_normal": false
}
Parameter
Type
Required
Description

accession_number

string

Unique ID

metadata

object

Study metadata

metadata_source

string

Identifies the source system of the metadata, enabling RADPAIR to apply processing rules for your specific integration. For example, if your organization has custom field mappings or specialized processing needs, providing this parameter allows RADPAIR to handle your metadata appropriately. Contact us during integration if you have custom metadata handling requirements.

native_id

string

A flexible identifier that links your system to ours. Unlike accession_number, which is required, native_id is optional and can be any string you choose, allowing you to store a unique reference from your system for easier tracking.

assigning_authority

string

Assigning authority

order_id

string

Order ID

site_id

string

Site ID

mrn

string

Patient MRN

draft_report

string

A pre-generated report draft that will be loaded into the report. This parameter is used within metadata object.

org_path

array

Org path

auto_create_suborgs

boolean

Auto-create sub-orgs

process_normal

boolean

When true, RADPAIR will attempt to process the report as “normal” upon creation according to your organization’s processing rules. Default: false.

pre_findings

object

Structured measurement data (typically from DICOM SR) that RADPAIR will process through an LLM to generate a formatted clinical summary. The formatted text is inserted into the transcript for radiologist review and editing. This parameter is used within the metadata object.

Example Metadata Structure:

Schema

{
  metadata: <METADATA>,
  metadata_source: <METADATA_SOURCE> // Optional - Identifies the origin of the metadata (typically organization or sub-organization name, but can be any value you choose)
  accession_number: <ACCESSION_NUMBER>, // Optional - Unique identifier for the report
  native_id: <NATIVE_ID>, // Optional
  assigning_authority: <ASSIGNING_AUTHORITY>, // Optional
  order_id: <ORDER_ID>, // Optional
  site_id: <SITE_ID>, // Optional
  mrn: <MRN>, // Optional
  org_path: <ORG_PATH>, // Optional - A unique identifier for sub-organizations or specific departments within an organization
  process_normal:  // Optional - Process as normal on creation (default: false)
}

Detailed payload structure

{
  "metadata": {
      "studyDescription": "X-ray of the hand metatarsal",
      "clinical_notes": "fractured left hand",
      "laterality": "left",
      "views": "2",
      "comparison": "feb 22 2023",
      "symptom": "Pain",
      "patient_age": "45",
      "patient_gender": "M",
      "draft_report": "xyz"// Optional "Patient presents with left hand pain and suspected fracture."  
  },
  "metadata_source": "xyzCorp" // Optional - Identifies the origin of the metadata (typically organization or sub-organization name, but can be any value you choose)
  "accession_number": "ACC12345",  // Optional - Unique identifier for the report
  "native_id": "NAT98765",  // Optional
  "mrn": "MRN123456",  // Optional
  "org_path": "Clinic_123"  // Optional - Unique identifier for a sub-organization or department within an organization
  "process_normal": true // Optional - Process as normal on creation
}

Response:

{ "report_id": <REPORT_ID> }
  • Receiving Report Updates: you can configure this via webhooks in the section below.

    Sample response:

    • Note: If process_normal is true, you may receive a report.processed update shortly after creation.

{
  // plain text version of the report
  final_report: <PLAIN_TEXT_REPORT>,
  report_id: <REPORT_ID>,
  // if the "Sign" button is clicked, the update_type
  // will be "sign". In the case of "Approve", it will be "approve"
  // After the report gets processed, this event will be emitted
  // with "mark_processed" update_type
  update_type: 'report.updated|report.signed|report.approved|report.processed'
  // HTML version of the report
  final_report_html: <HTML_REPORT>,
  accession_number: <ACCESSION_NUMBER>,
  native_id: <NATIVE_ID>,
  assigning_authority: <ASSIGNING_AUTHORITY>,
  order_id: <ORDER_ID>,
  site_id: <SITE_ID>,
  mrn: <MRN>,
  org_path: <ORG_PATH>
}

Response

{ "report_id": 12345, "error": null }

A Deeper Dive into Metadata and Its Role in Integration

Metadata plays a critical role in ensuring accurate preprocessing and template selection within RADPAIR. By structuring metadata correctly, integrators can enhance reporting accuracy and streamline workflows.

Key Metadata Fields

  • studyDescription (Highly Recommended) The studyDescription field is crucial for accurate preprocessing and template selection. It ensures that the correct study type and template are applied when creating a report.

  • Flexible Structure Metadata in RADPAIR is designed to be flexible, allowing users to include additional fields relevant to their workflow. While some fields influence system behavior, others can be customized to store structured data.

Metadata Fields Displayed in the UI

The following metadata fields are prominently displayed in the UI:

  • Clinical History

  • Comparison

  • Laterality

  • Views

These fields help provide context for reports and enhance usability for radiologists and other users.

Optional but Useful Metadata Fields

  • modality (e.g., "XR", "CT", "US") Helps refine template selection based on the imaging modality.

  • contrast (e.g., "IV contrast") Indicates whether contrast was used in the imaging study.

Metadata Flexibility and Customization

While certain metadata fields directly impact reporting accuracy and workflow efficiency, integrators can store additional structured data tailored to their needs. This flexibility allows for seamless adaptation to different radiology environments and organizational requirements.

Pre-Findings Processing

Overview

Pre-findings is a feature that automatically converts structured measurement data (typically from DICOM SR) into human-readable clinical summaries. When a study includes structured measurements in the pre_findings metadata field, RADPAIR processes this data through an LLM and inserts the formatted text into the transcript for radiologist review and editing.

API Payload Structure

{
  "metadata": {
    "pre_findings": {
      "report_info": { ... },
      "anatomical_findings": [ ... ]
    }
  }
}

Configuration

Organization-Level Settings

Admins can customize the processing prompt per organization via Organization Settings → Pre-findings.

Default System Prompt:

You are preparing data for incorporation into a radiology report. Please take the extracted DICOM SR data and format it concisely into a summary with one line per organ with a description of the organ, followed by the measurement. Where measurements are taken in 3 planes, format it as length × width × height. Any measurements should be rounded to one decimal place.

Example Output

Aorta – proximal 1.7 cm, mid 1.9 cm, distal 1.9 cm
Pancreas – head 1.3 cm, body 1.5 cm, tail 2.4 cm
Right kidney – 5.6 × 5.8 × 3.1 cm (vol 51.7 ml)


Finding a Report

Endpoint: POST https://api.radpair.com/integrations/reports/find

Request Body

{
  "accession_number": "string",
  "native_id": "string",
  "assigning_authority": "string",
  "order_id": "string",
  "site_id": "string",
  "mrn": "string",
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

accession_number

string

Unique Accession number

native_id

string

Additional ID

assigning_authority

string

Additional ID

order_id

string

Additional ID

site_id

string

Additional ID

mrn

string

Additional ID

org_path

array

Organizational path

Response

{
  "report": {
    "accession_number": "A12345",
    "events": [
      {
        "event_data": {
          "data": { "timestamp": 1741809758130 },
          "user_info": {
            "email": "[email protected]",
            "full_name": "Jane Doe",
            "id": 37,
            "role": "attending_radiologist"
          }
        },
        "event_type": "report.opened",
        "id": "8193e680-c743-4b82-882e-ae56c4f63afe",
        "report_id": 4152,
        "timestamp": 1741809758
      },
      {
        "event_data": {
          "data": { "timestamp": 1741809758131 },
          "user_info": {
            "email": "[email protected]",
            "full_name": "Jane Doe",
            "id": 37,
            "role": "attending_radiologist"
          }
        },
        "event_type": "report.closed",
        "id": "b33df3a3-c410-4a6a-a716-ce5639aaee17",
        "report_id": 4152,
        "timestamp": 1741809758
      },
      {
        "event_data": {
          "data": {},
          "user_info": {
            "email": "[email protected]",
            "full_name": "John Doe",
            "id": 38,
            "role": "attending_radiologist"
          }
        },
        "event_type": "report.discarded",
        "id": "c3d767b0-24f3-48b9-857a-883b48a52e59",
        "report_id": 4152,
        "timestamp": 1741813477
      },
      {
        "event_data": {
          "data": { "timestamp": 1741898217 },
          "user_info": {
            "email": "[email protected]",
            "full_name": "John Doe",
            "id": 38,
            "role": "attending_radiologist"
          }
        },
        "event_type": "report.processed",
        "id": "7614c949-2ea0-4033-b001-678d0912574c",
        "report_id": 4152,
        "timestamp": 1741898217
      }
    ],
    "final_report": "EXAM:\nXR Left Hand, 2 Views.\n\nCLINICAL HISTORY:\nPain. Fractured left hand, suspected. \n\nCOMPARISON:\n02/22/2023.\n\nFINDINGS:\n\nBONES:\nNo acute fracture or focal osseous lesion.\n\nJOINTS:\nNo dislocation. The joint spaces are normal. \n\nSOFT TISSUES:\nThe soft tissues are unremarkable.\n\nIMPRESSION:\n1. No acute osseous abnormality or displaced fracture identified.\n2. Consider MRI for further characterization of soft tissue injuries or disruption in the setting of ongoing pain.",
    "meta": {
      "clinical_history": "Pain\nfractured left hand, suspected",
      "clinical_notes": "fractured left hand",
      "comparison": "02/22/2023",
      "laterality": "left",
      "studyDescription": "X-ray of the hand metatarsal",
      "symptom": "Pain",
      "views": "2"
    },
    "is_drafting": true, // Whether the report is currently in draft mode for that user
    "mrn": "12345",
    "order_id": "ORDER950",
    "owner": "[email protected]",
    "report_id": 12345,
    "status": "addendum_signed"
  },
  "report_id": 12345
}

Notes

  • The response includes a full report object, including metadata, history of events, and the final report content.

  • The events array records interactions such as report opened, closed, discarded, and processed.

  • The meta section contains structured metadata fields relevant to the report.


Transferring Report Ownership

Endpoint: POST https://api.radpair.com/integrations/reports/transfer-ownership

Request Body

{
  "accession_number": "string",
  "email": "[email protected]",
  // Any other identifier used when report was created, e.g. mrn, native_id, etc
  "native_id": "string",
  "assigning_authority": "string",
  "order_id": "string",
  "site_id": "string",
  "mrn": "string",
  "org_path": ["Clinic A", "Department B"],
  "force": true
}
Parameter
Type
Required
Default
Description

accession_number

string

Report ID

email

string

New owner

native_id

string

Additional ID

assigning_authority

string

Additional ID

order_id

string

Additional ID

site_id

string

Additional ID

mrn

string

Additional ID

org_path

array

[ ]

Org path

force

boolean

false

When set to true, forces ownership transfer even if the report is currently locked or being

Notes

  • The force parameter allows administrators to transfer ownership regardless of the report's current state

  • Use with caution as it may interrupt another user's active editing session

  • When force is true, the current owner will receive a notification that ownership has been transferred

    \

Response

{ "report_id": 12345, "new_owner_email": "[email protected]" }

Transferring a Report to another Organization

This endpoint transfers a report from one organization to another within the system. It locates a report using provided identifiers (like accession number or MRN) within a source organization and moves it to a target organization specified by their respective org paths.

Endpoint: POST https://api.radpair.com/integrations/reports/transfer-org

Request Body:

request.json
{
  "report_identifiers": {
    "accession_number": "string",
    "native_id": "string",
    "assigning_authority": "string",
    "order_id": "string",
    "site_id": "string",
    "mrn": "string"
  },
  "source_org_path": ["Clinic A", "Department B"],
  "target_org_path": ["Clinic C", "Department D"]
}

Parameters

Parameter
Type
Required
Description

report_identifiers

object

Object containing report identifiers (at least one required)

source_org_path

array

Source organization path where report currently exists

target_org_path

array

Target organization path where report will be transferred

Report Identifiers (at least one required)

Parameter
Type
Required
Description

accession_number

string

Unique Accession number

native_id

string

Additional ID

assigning_authority

string

Additional ID

order_id

string

Additional ID

site_id

string

Additional ID

mrn

string

Additional ID

Response

response.json
{
  "report_id": 12345,
  "report": {
    // Full report object with updated organization
  }
}

Error Responses

Status Code
Error Key
Description

403

(varies)

ReportingService exception (insufficient permissions, etc.)

500

TRANSFER_REPORT_ORG_ERROR

Unexpected error during transfer


Canceling a Report

Endpoint: POST https://api.radpair.com/integrations/reports/cancel

Request Body

{
  "accession_number": "string",
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

accession_number

string

Report ID

org_path

array

Org path

Response

{ "status": "success" }

Checking Report Access

Endpoint: POST https://api.radpair.com/integrations/reports/<REPORT_ID>/can-access

Request Body

{
  "email": "[email protected]",
  "accession_number": "string",
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

email

string

User email

accession_number

string

Report ID

org_path

array

Org path

Response

{ "can_access": true, "reason": null }

Deleting a Report

Endpoint: POST https://api.radpair.com/integrations/reports/delete

Request Body

{
  "accession_number": "string",
  "native_id": "string",
  "assigning_authority": "string",
  "order_id": "string",
  "site_id": "string",
  "mrn": "string",
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

accession_number

string

Unique Accession number

native_id

string

Additional ID

assigning_authority

string

Additional ID

order_id

string

Additional ID

site_id

string

Additional ID

mrn

string

Additional ID

org_path

array

Organizational path

Response

{ "status": "success" }

Update Report Status Endpoint

Endpoint:POST https://api.radpair.com/integrations/reports/status-update

Request Body

{
  "status": "DRAFT",
  "accession_number": "ABC12345",
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

status

string

New status for the report (DRAFT or CANCELLED)

accession_number

string

Report identifier (required if no other ID is present)

native_id

string

Alternate identifier for the report

assigning_authority

string

Alternate identifier for the report

order_id

string

Optional report ID from order system

site_id

string

Optional site ID for additional context

mrn

string

Medical record number

org_path

array

Organizational hierarchy path

* At least one identifying field (accession_number, native_id, order_id, etc.) is required to locate the report.

Allowed Status Values:

  • DRAFT

  • CANCELLED

Response

{
  "report_id": "a1b2c3",
  "report": { /* report metadata */ },
  "new_status": "DRAFT"
}

Errors

  • STATUS_REQUIRED: If status is missing from the request

  • INVALID_STATUS: If the provided status is not one of the allowed values

  • UPDATE_REPORT_STATUS_ERROR: If an error occurs during database update

Notes:

  • This is a temporary implementation. A more robust and traceable event-handling system is planned.

  • Make sure the report being updated is accessible to the authenticated organization context.

Linking Reports

This endpoint links multiple reports together, creating a group. Reports in a group share content (transcript, final report, and metadata) while maintaining individual identity (label, id).

Endpoint:POST https://api.radpair.com/integrations/reports/link

Request Body

{
  "reports": [
    {
      "accession_number": "ACC001",
      "native_id": "NAT001",
      "order_id": "ORD001"
    },
    {
      "accession_number": "ACC002",
      "native_id": "NAT002",
      "order_id": "ORD002"
    }
  ],
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

reports

array

Array of report identifiers (at least 2 reports needed)

org_path

array

Organization path

Notes

  • Each report in the array needs at least one identifier (accession_number, native_id, etc.)

  • Reports must have the same MRN to be linked

  • Only reports with "unread" or "draft" status can be linked

  • The first report becomes the default report for the group

Response

{ "status": "success" }

Error Responses

  • 400: Bad Request - Invalid request format or parameters (e.g., INVALID_REPORTS if fewer than 2 reports provided)

  • 500: REPORT_LINKING_ERROR - Error occurred during linking with detailed error message


Unlinking Reports

This endpoint removes reports from a group. When a report is unlinked, it returns to its original state.

Endpoint:POST https://api.radpair.com/integrations/reports/unlink

Request Body

{
  "reports": [
    {
      "accession_number": "ACC001",
      "native_id": "NAT001",
      "order_id": "ORD001"
    }
  ],
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

reports

array

Array of report identifiers to unlink

org_path

array

Organization path

Notes

  • Only reports with "unread" or "draft" status can be unlinked

  • Unlinking restores the report to its original state (before it was linked)

  • Other reports in the group remain linked

Response

{ "status": "success" }

Error Responses

  • 400: Bad Request - Invalid request format or parameters (e.g., MISSING_REPORTS if no reports provided)

  • 500: REPORT_UNLINKING_ERROR - Error occurred during unlinking with detailed error message


Update Identifiers

Update report identifiers. Useful for synchronizing changes in accession numbers, order IDs, or MRNs across reports.

Endpoint:POST https://api.radpair.com/integrations/reports/update-identifiers

Request Body

{
    {
      "source_identifiers": {
        "accession_number": "MOUADACCD1",
        "order_id": "MOUADORDERD1",
        "mrn": "XXXXXX"
      },
      "target_identifiers": {
        "accession_number": "MOUADACCD1U",
        "order_id": "MOUADORDERD1U",
        "mrn": "XXXXXX"
      }
}
Parameter
Type
Required
Description

source_identifiers

object

Original set of identifiers for each report.

target_identifiers

object

New set of identifiers to apply.

accession_number

string

Report accession number.

order_id

string

Report order ID.

mrn

string

Medical record number.

Response

{
  "status": "success",
  "updated_report": [
    {
      "accession_number": "MOUADACCD1U",
      "order_id": "MOUADORDERD1U",
      "mrn": "XXXXXX"
      /* other public fields */
    },
    {
      "accession_number": "MOUADACCD2U",
      "order_id": "MOUADORDERD2U",
      "mrn": "XXXXXX"
    }
  ],
}
Field
Type
Description

status

string

"success" if changes applied without error.

updated_report

array

List of public report objects reflecting new identifiers.


Copying Reports

This endpoint copies specified fields from a source report to a target report. Both reports must exist and be accessible within the organization.

Endpoint: POST https://api.radpair.com/integrations/reports/copy

Request Body

{
  "source_identifiers": {
    "accession_number": "ACC001",
    "native_id": "NAT001"
  },
  "target_identifiers": {
    "accession_number": "ACC002", 
    "native_id": "NAT002"
  },
  "fields": ["transcript", "final_report", "meta"],
  "org_path": ["Clinic A", "Department B"]
}
Parameter
Type
Required
Description

source_identifiers

object

Identifiers for the source report to copy from

target_identifiers

object

Identifiers for the target report to copy to

fields

array

Array of field names to copy (defaults to all copyable fields)

org_path

array

Organization path for target organization

Available Fields to Copy

  • transcript - Report transcript content

  • final_report - Final report content

  • meta - Report metadata

  • status - Report status

  • is_drafting - Drafting state

  • template - Template ID

  • study - Study ID

Notes

  • Both source and target reports must exist and be accessible

  • If no fields are specified, all copyable fields are copied

  • Invalid field names will result in a 400 error

  • Copy operation is atomic - either all fields copy successfully or none do

  • Target report fields are overwritten with source report values

Response

{
  "status": "success",
  "report": {
    "id": "report_id",
    "accession_number": "ACC002",
    "transcript": "copied transcript content",
    "final_report": "copied final report content",
    "meta": {...},
    "status": "copied_status"
  }
}

Error Responses

  • 400: Bad Request - Invalid field names or copy operation failed

  • 404: Report not found - Source or target report not found

  • 500: COPY_REPORT_ERROR - Database error during copy operation


Integration Preview

Webhooks

We have transitioned from using Socket.IO for event communication to a webhook-based system. This change improves scalability, reliability, and flexibility in delivering events to your systems.

What You Need to Do

To continue receiving events, you must migrate to webhooks by following these steps:

1. Set Up Your Webhook Endpoint

  • Create a publicly accessible HTTP endpoint (must support HTTPS).

  • Ensure the endpoint can handle POST requests with JSON payloads.

2. Register Your Webhook

  • Use our portal to register your webhook URL and specify the events you want to subscribe to.

    • Navigate to the Organizations page

    • Click on the "⋮" button for your organization (or any sub-organization) and hit "Setup webhooks":

    • Here, you'll be able to create, edit and view all your webhook configurations for the given organization:

    • Click on "Create New" to setup a new webhook. Specify the URL, the event types you want to listen to and submit the form:

    • Once created, you'll get a "Signing Secret." Keep that somewhere safe!

Verifying Webhook Messages

To ensure the integrity of the messages your application receives, you should validate the webhook signature included in the message. This prevents unauthorized access and ensures the message was sent by us.

Signature Details

  • Algorithm: HMAC-SHA256

  • Header: X-Webhook-Signature

  • Signing Secret: Your secret key (provided in your account settings)

  • Payload Canonicalization: JSON payload is canonicalized before signing by:

    • Sorting all keys alphabetically.

    • Using , as the separator for array elements and : for key-value pairs.

    • Removing unnecessary spaces.

Sample Code

SECRET = "your-secret-key"

def verify_signature(request):
    received_signature = request.headers.get("X-Webhook-Signature")
    if not received_signature:
        raise ValueError("Missing X-Webhook-Signature header")

    # Get the raw request payload
    payload = request.data 

    # Compute the expected signature
    expected_signature = hmac.new(
        SECRET_KEY.encode("utf-8"),
        payload,
        hashlib.sha256
    ).hexdigest()

    # Use a timing-safe comparison
    return hmac.compare_digest(received_signature, expected_signature):
        raise ValueError("Invalid signature")

    return True

Webhook Events

RADPAIR sends webhook events for various report actions. All webhook events follow this general structure:

{
  "event": "event.name",
  "timestamp": "ISO-8601 timestamp",
  "payload": {
    "data": {
      "timestamp": 1742577136992
    },
    "user_info": {
      "id": 123,
      "email": "[email protected]",
      "full_name": "User Name",
      "role": "user_role"
    },
    "report_info": {
      "report_id": 456,
      "report_label": null,
      "report_status": "status",
      "order_id": "ORDER_ID",
      "accession_number": "ACCESSION_NUMBER",
      // The metadata is only provided in sign events
      "metadata": {
        "studyDescription": "X-ray of the hand metatarsal",
        "clinical_notes": "fractured left hand",
        "laterality": "left",
        "views": "4",
        "comparison": "feb 22 2023",
        "symptom": "Pain"
        // And any other custom or additional fields provided 
        // when creating the report
      }
    }
  },
  "webhook_version": "1.0"
}

Available Events

Event
Description
Additional Data

report.created

New report was created

Report creation details

report.opened

Report was opened

timestamp: Unix timestamp in ms

report.closed

Report was closed

timestamp: Unix timestamp in ms

report.dictated

Dictation occurred

dictation_start_time_ms, dictation_stop_time_ms

report.saved

Report was saved

Varies based on save type

report.processed

Report was processed

timestamp: Unix timestamp in ms

report.impressions_processed

Impressions were processed

Varies

report.discarded

Report was discarded

Varies

report.discarded_completely

Report was completely discarded

Varies

report.unlocked

Report was unlocked

Varies

report.prelim_signed

Report was signed by a resident

html_final_report & final_report HTML and plain text version of the report

report.signed

Report was signed by an attending

html_final_report & final_report HTML and plain text version of the report

report.addendum_prelim_signed

Addendum was signed by a resident

html_final_report & final_report HTML and plain text version of the report

report.addendum_signed

Addendum was signed by an attending

html_final_report & final_report HTML and plain text version of the report

report.approved

Legacy event, equivalent to signed

html_final_report & final_report HTML and plain text version of the report

report.updated

Report content was updated

final_report: Plain text version of the report

report.mark_processed

Report was marked as processed

final_report, html_final_report, timestamp: Unix timestamp in ms

report.owner_changed

Report ownership changed

New owner information

report.status_changed

Report status changed

Previous and new status information

report.linked

Reports were linked together

identifiers_list, group_id, report_ids

report.unlinked

Reports were unlinked

identifiers_list, group_id, report_ids

report.identifiers_updated

Report identifiers were updated

Updated identifier information

report.published

Report was published to RIS/PACS

sign_context, publish_context, idempotency_key

report.published_cancelled

Scheduled publication was cancelled

cancelled_at, remaining_seconds, reason

Example: Report Opened Event

{
  "event": "report.opened",
  "timestamp": "2025-03-17T19:06:34.289782+00:00",
  "payload": {
    "data": {
      "timestamp": 1742238394168
    },
    "user_info": {
      "id": 29,
      "email": "[email protected]",
      "full_name": "User Name",
      "role": "radiologist_admin"
    },
    "report_info": {
      "report_id": 456,
      "report_label": null,
      "report_status": "status",
      "order_id": "ORDER_ID",
      "accession_number": "ACCESSION_NUMBER",
    },
  },
  "webhook_version": "1.0"
}

Example: Report Dictated Event

{
  "event": "report.dictated",
  "timestamp": "2025-03-17T16:15:34.868720+00:00",
  "payload": {
    "data": {
      "dictation_start_time_ms": 1742228120497,
      "dictation_stop_time_ms": 1742228134628
    },
    "user_info": {
      "id": 37,
      "email": "[email protected]",
      "full_name": "User Name",
      "role": "resident"
    },
    "report_info": {
      "report_id": 456,
      "report_label": null,
      "report_status": "status",
      "order_id": "ORDER_ID",
      "accession_number": "ACCESSION_NUMBER",
    },
  },
  "webhook_version": "1.0"
}

Example: Report Preliminary Signed Event

{
  "event": "report.prelim_signed",
  "timestamp": "2025-03-17T16:19:52.633577+00:00",
  "payload": {
    "data": {
      "html_final_report": "<HTML_FINAL_REPORT>",
      "final_report": "<FINAL_REPORT>",
      // All sign events for mammo studies will include the below
      "exam_specific_data": {
        "breast_imaging_mammo": {
            "birads_category": "3",
            "breast_density": "Heterogeneously dense'",
            "follow_up_interval_type": "6 month",
            "laterality": "Bilateral"
        }
      }
    },
    "user_info": {
      "id": 38,
      "email": "[email protected]",
      "full_name": "User Name",
      "role": "resident"
    },
    "report_info": {
      "report_id": 4173,
      "report_label": null,
      "report_status": "prelim_signed",
      "order_id": "ORDER_ID_123",
      "accession_number": "ACC_456"
      // All sign events include an aggregate of the metadata provided 
      // during creating and updating the report
      "metadata": {
        "studyDescription": "X-ray of the hand metatarsal",
        "clinical_notes": "fractured left hand",
        "laterality": "left",
        "views": "4",
        "comparison": "feb 22 2023",
        "symptom": "Pain"
      }
        },
  "webhook_version": "1.0"
}

Example: Report Processed Event

{
  "event": "report.processed",
  "timestamp": "2025-03-17T19:23:32.153561+00:00",
  "payload": {
    "data": {
      "timestamp": 1742239412
    },
    "user_info": {
      "id": 29,
      "email": "[email protected]",
      "full_name": "User Name",
      "role": "radiologist_admin"
    },
  },
  "webhook_version": "1.0"
}

Report Recall Webhook Integration

Audience: Integration partners, RIS/PACS vendors, and webhook consumers

Overview

When Report Recall (Oops Factor) is enabled, the publication workflow changes from a single signed event to a two-stage process:

1

report.signed

Fires immediately when user signs (any variant: prelim, final, addendum).

2

report.published

Fires when report is finalized (either after timer expires or user expedites).

Why This Matters for Your Integration

Report Recall requires webhook integration to function properly. Unlike simpler features that rely solely on the user interface, Report Recall introduces a two-stage publication workflow that your integration must handle correctly.

The Problem with Traditional Integrations

Traditional integrations listen only to the signed event to know when a report is complete. However, with Report Recall enabled:

  • The signed event fires immediately when the radiologist clicks Sign, but the report is not yet finalized

  • A countdown timer begins (configurable delay, typically 20–120 seconds)

  • The report may be recalled and edited during this window

  • The published event fires only when the timer expires OR the user clicks "Publish Now"

What This Means for You

Your integration must distinguish between:

  • Reports that are signed but still in the recall window (potentially subject to changes)

  • Reports that are truly finalized and ready to commit to your RIS/PACS system

Without proper handling, you risk:

  • Committing reports that are later recalled and modified

  • Missing user-expedited publications ("Publish Now" button clicks)

  • Receiving delayed published events for previous reports while working on new ones

  • Poor user experience (iframe not closing at the right time)

This guide provides two robust integration patterns to handle Report Recall correctly, along with edge case handling, migration guidance, and testing procedures.

Integration Requirements

To properly support Report Recall, your integration should listen to both events:

Event
Purpose
When to Use

report.signed

User completed signing

Close iframe, move to next report, update UI

report.published

Report finalized for RIS/PACS

Commit final report to your system, close pending workflows

Report Recall Event Payloads

report.signed Event

Fires immediately when user clicks Sign (any variant: prelim, final, addendum).

{
  "event": "report.signed",
  "payload": {
    "data": {
      "sign_context": {
        "sign_type": "sign",
        "new_status": "signed",
        "signed_at": "2025-10-22T15:30:00Z",
        "sign_payload": { }
      }
    },
    "user_info": {
      "id": 123,
      "email": "[email protected]",
      "full_name": "Dr. Jane Smith",
      "role": "radiologist"
    },
    "report_info": {
      "report_id": 12345,
      "accession_number": "ACC123456",
      "mrn": "MRN789",
      "study_id": "STU456",
      "report_status": "signed",
      "is_drafting": false,
      "metadata": { },
      "events": [ ]
    }
  }
}

report.published Event

Fires when report is finalized (either timer expiration or user-expedited).

{
  "event": "report.published",
  "payload": {
    "data": {
      "sign_context": {
        "sign_type": "sign",
        "new_status": "signed",
        "signed_at": "2025-10-22T15:30:00Z",
        "sign_payload": { }
      },
      "publish_context": {
        "trigger": "timer_expired",
        "delay_seconds": 60,
        "published_at": "2025-10-22T15:31:00Z"
      },
      "idempotency_key": "report_12345_sign"
    },
    "user_info": {
      "id": 123,
      "email": "[email protected]",
      "full_name": "Dr. Jane Smith",
      "role": "radiologist"
    },
    "report_info": {
      "report_id": 12345,
      "accession_number": "ACC123456",
      "mrn": "MRN789",
      "study_id": "STU456",
      "report_status": "signed",
      "is_drafting": false,
      "metadata": { }
    }
  }
}

Key Field: publish_context.trigger

This is the critical field for handling Report Recall correctly.

The trigger field indicates why the report was published:

Value
Meaning
Integration Action

timer_expired

Countdown timer reached zero

⚠️ Verify this is the expected report (check accession_number or report_id) before closing workflows

user_overridden

User clicked "Publish Now"

✅ Safe to immediately close iframe/workflow for this report

recall_disabled

Organization has recall disabled

✅ Treat as immediate publish (no delay occurred)

Why trigger Matters:

Scenario: A radiologist signs Report A, moves to Report B, and then the timer expires for Report A.

Without checking trigger:

  • Your integration receives published for Report A

  • Blindly closes the current iframe

  • User could be kicked out of Report B unexpectedly

With trigger checking:

  • Receives published with trigger: "timer_expired" for Report A

  • Checks if Report A is still the active report (via accession_number or report_id)

  • If not, commits to RIS but doesn't close iframe

  • User continues working on Report B without interruption

Migration Guide

If You Currently Listen to signed Only

Problem: You'll miss user-expedited publications ("Publish Now" button clicks).

Solution:

1

Add report.published webhook listener

2

Check trigger field:

  • user_overridden: Commit to RIS immediately

  • timer_expired: Verify it's expected, then commit

  • recall_disabled: Commit immediately (no delay)

3

Keep existing signed listener for iframe navigation

Testing Your Integration

Test Scenarios

Scenario
Steps
Expected Behavior

Normal flow

Sign → wait for timer → observe

published received with trigger: "timer_expired"

Expedited

Sign → click "Publish Now" → observe

published received with trigger: "user_overridden"

Cancelled

Sign → click "Cancel" → observe

publish_cancelled received, no published

Multiple reports

Sign Report A → move to Report B → sign Report B

Correct pairing of events, no race conditions

Recall disabled

Sign with recall disabled org

published fires immediately with trigger: "recall_disabled"

Frequently Asked Questions

Q: Do I need to change anything if recall is disabled for an org?

A: No. When recall is disabled, published fires immediately after signed with trigger: "recall_disabled". Your integration works the same way - just with zero delay.

Q: What if I receive `published` before `signed`?

A: This should never happen. The system guarantees signed fires before published. If you observe this, file a bug report with the timestamp and payload.

Q: Can I ignore `signed` and only use `published`?

A: Yes, but UX could because the iframe won't close until publication (20–120 seconds later). Recommended to use both for optimal experience.

Q: What happens if my webhook endpoint is down when events fire?

A: Webhook delivery includes automatic retries with exponential backoff. Check the webhook delivery logs in your dashboard for failure details.

Q: Can different organizations have different delay times?

A: Yes. Each organization configures their own delay_seconds (20–120 seconds). The publish_context.delay_seconds field in the payload tells you what delay was configured.

Q: Should I use `report_id` or `accession_number` for tracking?

A: Both are provided. Use report_id (internal ID, guaranteed unique) for internal tracking, and accession_number (external identifier) for matching with your RIS/PACS.


User Roles and Statuses

User Roles

When creating users or generating tokens, you can specify a user role that determines what actions they can perform. If not specified, users are assigned the attending_radiologist role by default.

Role
Description

attending_radiologist

Default role with full access to signing reports

resident

Can sign preliminary reports but not final reports

report_drafter_two

Can edit both transcript and final report

report_drafter_one

Can only edit transcript

radiologist_admin

Administrative role with all attending radiologist permissions

To specify a role when creating a user or token, include the user_role parameter:

{
  "user_email": "[email protected]",
  "first_name": "John",
  "last_name": "Doe",
  "user_role": "resident",
  "org_path": ["Clinic West", "Radiology"]
}

Role Permissions

Roles follow an inheritance hierarchy where higher-level roles inherit all permissions from lower-level roles:

radiologist_admin

attending_radiologist

resident

report_drafter_two

report_drafter_one
Role
Permissions
Inherits From

report_drafter_one

Edit transcript

None

report_drafter_two

Edit final report

report_drafter_one

resident

Sign preliminary reports, Sign preliminary addendums

report_drafter_two

attending_radiologist

Sign final reports, Sign addendums

resident

radiologist_admin

Administrative functions

attending_radiologist

Report Statuses

Reports can have the following statuses:

Status
Description

unread

Default status for new reports

draft

Report is in progress

prelim_signed

Report has been signed by a resident

signed

Report has been signed by an attending radiologist

addendum_prelim_signed

Addendum has been signed by a resident

addendum_signed

Addendum has been signed by an attending radiologist

cancelled

Report has been cancelled

approved

Legacy status, equivalent to signed

Clinical Validation Process

Before transitioning from the staging environment to production, all integrations with RADPAIR must undergo a clinical validation process conducted by RADPAIR's internal radiologists and QA specialists. This ensures that the integration meets clinical safety, accuracy, and workflow requirements before being deployed in a live setting.

Purpose of Clinical Validation

  • Clinical Accuracy: Verify that reports generated through the integration are complete, properly structured, and clinically sound.

  • Workflow Compliance: Ensure that the integration aligns with expected radiology reporting workflows and does not introduce errors or inefficiencies.

  • System Integrity: Confirm that data is processed correctly, with no unintended modifications to medical content.

What the Validation Process Involves

  1. Test Cases in Staging RADPAIR's clinical team will generate, review, and process sample reports using your integration.

  2. Detailed QA Review Our radiologists and QA specialists will assess the reports for formatting, accuracy, and compliance with standard reporting practices.

  3. Issue Resolution If any discrepancies or issues are found, RADPAIR will work with you to address them before approval.

Steps to Approval

  1. RADPAIR Conducts Clinical Testing Our team will test your integration using real-world scenarios to ensure it functions correctly.

  2. Validation Report & Feedback You will receive a summary of the validation results, including any necessary adjustments.

  3. Final Sign-Off Once all criteria are met, RADPAIR will approve the transition to the external environment.

This clinical validation is a critical step to ensure that all integrations with RADPAIR maintain the highest standards of accuracy, reliability, and clinical usability.

Miscellaneous

Mammo Specific Sign Events

These are specialized metadata structures extracted during the signing of mammography reports, ultrasound reports with "Breast" in the name, and MRI studies with "Breast" in the name. This section outlines how metadata is extracted, valid options, and example payloads for each study type.


Report Metadata Extraction Rules

Study Type Conditions

The system extracts metadata based on the following study types:

  • Mammogram (MG)

  • Ultrasound (US) with "Breast" in the study name (case-insensitive)

  • MRI (MR) with "Breast" in the study name (case-insensitive)


Metadata Categories

1. Lung Cancer Screening Reports

{
  "lung_cancer_screening": {
    "lung_rads_category": "<LUNG_RADS_CATEGORY>",
    "incomplete_reason": "<INCOMPLETE_REASON>",
    "modifier": "<MODIFIER>",
    "follow_up_recommendations": "<FOLLOW_UP_RECOMMENDATION>"
  }
}

Valid Options:

  • lung_rads_category: "0", "1", "2", "3", "4A", "4B", "4X", "0S", "1S", "2S", "3S", "4AS", "4BS", "4XS"

  • incomplete_reason: "Prior comparison needed", "Part of lungs cannot be evaluated", "Inflammatory or Infectious process"

  • modifier: "N", "S"

  • follow_up_recommendations: "1-3 month LDCT", "12-month screening", "6-month LDCT", "3-month LDCT or PET", "Referral", "Diagnostic CT or PET/Bx"


2. Breast Imaging Mammogram Reports

{
  "breast_imaging_mammo": {
    "breast_density": "<BREAST_DENSITY>",
    "birads_category": "<BIRADS_CATEGORY>",
    "follow_up_interval_type": "<FOLLOW_UP_INTERVAL_TYPE>",
    "laterality": "<LATERALITY>"
  }
}

Valid Options:

  • breast_density: "Fatty", "Scattered", "Heterogenous", "Very Dense"

  • birads_category: "0", "1", "2", "3", "4", "4A", "4B", "4C", "5", "6", "Post Procedure"

  • follow_up_interval_type: "12 month", "18 month", "2 year", "3 month", "6 month", "Addtl Imaging", "Age 35-40", "Bx", "Galactogram", "Immediate", "No follow-up", "US", "Diagnostic Priors", "US Bx", "Stereotactic Bx"

  • laterality: "Bilateral", "Left", "Right"


3. Breast Imaging MRI Reports

{
  "breast_imaging_mri": {
    "birads_category": "<BIRADS_CATEGORY>",
    "follow_up_interval_type": "<FOLLOW_UP_INTERVAL_TYPE>"
  }
}

Valid Options:

  • birads_category: "0", "1", "2", "3", "4", "4A", "4B", "4C", "5", "6"

  • follow_up_interval_type: "Other", "Addtl Imaging", "Routine MRI", "6-month", "Surgical", "Bx"


4. Breast Imaging Ultrasound Reports

{
  "breast_imaging_us": {
    "birads_category": "<BIRADS_CATEGORY>"
  }
}

Valid Options:

  • birads_category: "0", "1", "2", "3", "4", "4A", "4B", "4C", "5", "6"


Example Payloads

Mammogram Report Example

{
  "html_final_report": "...",
  "final_report": "...",
  "timestamp": 1743796612114,
  "exam_specific_data": {
    "breast_imaging_mammo": {
      "breast_density": "Heterogeneously",
      "birads_category": "3",
      "follow_up_interval_type": "No follow-up",
      "laterality": "Bilateral"
    }
  }
}

Ultrasound Report Example

{
  "html_final_report": "...",
  "final_report": "...",
  "timestamp": 1743796988602,
  "exam_specific_data": {
    "breast_imaging_us": {
      "birads_category": "1"
    }
  }
}

MRI Report Example

{
  "html_final_report": "...",
  "final_report": "...",
  "timestamp": 1743797202435,
  "exam_specific_data": {
    "breast_imaging_mri": {
      "birads_category": "1",
      "follow_up_interval_type": "Routine MRI"
    }
  }
}

Draft Report

A pre-generated report draft that will be loaded into the report. If you have a report that you want to drop into RADPAIR you can use this parameter. This bypasses ai layers for extracting metadata and normal processing. This is ideal for if you have a pregenerated report and you want to drop it into the final report box.

{
  "accession_number": "string",
  "metadata": {
    "studyDescription": "string",
    "clinical_notes": "string",
    "draft_report": "string",
  },
}

Legacy Authentication and Endpoints

Creating a Token

  1. Admin Authentication Request: Admins authenticate themselves using their own username and password and send a POST request to RADPAIR to generate an access token for a specific user:

    url: https://api.radpair.com/users/orgs/sign_in
    requestKind: POST
    headers:
      basicAuth:
        type: http
        scheme: basic
        description: The admin username and password
    bodyContentType: JSON
    bodyProperties:
      user_email:
        type: string
        description: The email of the user for whom the access token is being generated.
      first_name:
        type: string
        description: The user's first name, used during the registration step
      last_name:
        type: string
        description: The user's last name, used during the registration step
      user_role:
        type: string
        description: (Optional) The user's role. Valid values are "attending_radiologist" (default), "resident", "report_drafter_one", "report_drafter_two", or "radiologist_admin".
      internal_org_id:
        type: string
        description: (Optional) This field is not required. However, use it to specify a unique ID (name) for sub-organizations or sub-practices, if applicable.
    responses:
      "200":
        bodyContentType: JSON
        bodyProperties:
          access_token:
            type: string
            description: the access token used to authenicate a user
      "400":
        description: Bad Request - Invalid request format or parameters
      "401":
        description: Unauthorized
      "500":
        description: Internal Server Error
  • Admin Authentication Request

    POST /users/orgs/sign_in HTTP/1.1
    Host: api.radpair.com
    Authorization: Basic YWRtaW5fdXNlcm5hbWU6YWRtaW5fcGFzc3dvcmQ=
    Content-Type: application/json
    
     {
     "user_email": "[email protected]",
     "first_name": "John",
     "last_name": "Doe",
     "user_role": "resident",
     "internal_org_id": "clinic_1"
     }
  1. Using the Access Token:

    • This access_token is essential for authenticating subsequent user sessions and actions.

Creating Report

url: https://api.radpair.com/reports/intgt/create
requestKind: POST
headers:
  basicAuth:
    type: http
    scheme: basic
    description: The admin username and password
bodyContentType: JSON
bodyProperties:
  metadata:
    type: object
    description: (Optional)
  metadata_source:
    type: string
    description: (Optional) e.g. name of your org or sub-org.
                 Note: For best results, please communicate with us what metadata you can provide
                 and the value of this field in advance so we can process it accordingly.
  accession_number:
    type: string
    description: (Required) 
  native_id:
    type: string
    description: (Optional) A flexible identifier that links your system to ours. 
                 Unlike `accession_number`, which is required, `native_id` is optional and can be any string you choose, allowing you to store a unique 
                 reference from your system for easier tracking.
  assigning_authority:
    type: string
    description: (Optional) The assigning authority is a unique name of the system (or organization or agency or department) that creates the data.
  order_id:
    type: string
    description: (Optional) A unique order reference number.
  site_id:
    type: string
    description: (Optional) Identifier for the reporting site or facility.
  mrn:
    type: string
    description: (Optional) MRN is encrypted on our end.
  internal_org_id:
    type: string
    description: (Optional) This field is not required. However, use it to specify a unique ID (name) for sub-organizations or sub-practices, if applicable.
responses:
  "200":
    bodyContentType: JSON
    bodyProperties:
      report_id:
        type: number
        description: the ID for the report created
      error:
        type: string
        description: any errors that occurred during the report creation
    description: Report successfully created
  "400":
    description: Bad Request - Invalid request format or parameters
  "401":
    description: Unauthorized
  "500":
    description: Internal Server Error

Report Ownership Transfer

Reports created via the accession_number are tied to the user that invoked the create_report mentioned above. If there's a need to transfer the ownership of the report, you can invoke the endpoint below:

url: https://api.radpair.com/reports/intgt/transfer-ownership
requestKind: POST
headers:
  basicAuth:
    type: http
    scheme: basic
    description: The admin username and password
bodyContentType: JSON
bodyProperties:
  accession_number:
    type: string
    description: (Required) 
  native_id:
    type: string
    description: (Optional) A flexible identifier that links your system to ours. 
                 Unlike `accession_number`, which is required, `native_id` is optional and can be any string you choose, allowing you to store a unique 
                 reference from your system for easier tracking.
  assigning_authority:
    type: string
    description: (Optional) TThe assigning authority is a unique name of the system (or organization or agency or department) that creates the data.
  order_id:
    type: string
    description: (Optional) A unique order reference number.
  site_id:
    type: string
    description: (Optional) Identifier for the reporting site or facility.
  mrn:
    type: string
    description: (Optional) MRN is encrypted on our end.
  internal_org_id:
    type: string
    description: (Optional) This field is not required. However, use it to specify a unique ID (name) for sub-organizations or sub-practices, if applicable.
  email:
    type: string
    description: The email address of the new owner. If blank, the report will be reset/transferred back to the admin user.
responses:
  "200":
    bodyContentType: JSON
    bodyProperties:
      report_id:
        type: number
        description: the ID for the report created
      error:
        type: string
        description: any errors that occurred during the report creation
    description: Report successfully created
  "400":
    description: Bad Request - Invalid request format or parameters
  "401":
    description: Unauthorized
  "500":
    description: Internal Server Error

Checking for Access

You can check if a given user has access to a given report using the endpoint below:

url: https://api.radpair.com/reports/intgt/<RADPAIR_REPORT_ID>/can-access
requestKind: POST
headers:
  basicAuth:
    type: http
    scheme: basic
    description: The admin username and password
bodyContentType: JSON
bodyProperties:
  email:
    type: string
    description: the user email we want to check report access for
  accession_number:
    type: string
    description: (Required) 
  native_id:
    type: string
    description: (Optional) A flexible identifier that links your system to ours. 
                 Unlike `accession_number`, which is required, `native_id` is optional and can be any string you choose, allowing you to store a unique 
                 reference from your system for easier tracking.
  assigning_authority:
    type: string
    description: (Optional) TThe assigning authority is a unique name of the system (or organization or agency or department) that creates the data.
  order_id:
    type: string
    description: (Optional) A unique order reference number.
  site_id:
    type: string
    description: (Optional) Identifier for the reporting site or facility.
  mrn:
    type: string
    description: (Optional) MRN is encrypted on our end.
  internal_org_id:
    type: string
    description: (Optional) This field is not required. However, use it to specify a unique ID (name) for sub-organizations or sub-practices, if applicable.
responses:
  "200":
    bodyContentType: JSON
    bodyProperties:
      can_access:
        type: boolean
        description: whether or not the given user email has access to this report
      reason:
        type: string
        description: if can_access is false, this can provide an explanation when applicable
  "400":
    description: Bad Request - Invalid request format or parameters
  "401":
    description: Unauthorized
  "500":
    description: Internal Server Error

Feedback & Support

This guide outlines the essential steps for integrating RADPAIR into your application, from initial setup to leveraging the application’s full capabilities. For further assistance or clarification, please contact RADPAIR support.

Last updated