Process Overview


The following overview provides comprehensive guidance for developers on the process of registering their FHIR (Fast Healthcare Interoperability Resources) application for various EHRs including Veradigm EHR, Altera products: TouchWorks, Sunrise, and Paragon as well as dbMotion. Whether you're developing for one or all of these products, this overview will serve as an invaluable guide to streamline the registration process and facilitate the deployment of your FHIR application.


The Veradigm and Altera FHIR API R4 release is our third FHIR API. We released our first in 2017 to support the MU3 requirement for a patient-facing API based on an open standard, and then soon after we released an R3 (STU3) version for UK clients. Our developers participate in the Argonaut Project and the Da Vinci Project, as well as HL7 FHIR Accelerator Program projects like FHIR at Scale Taskforce (FAST). We also participate in HL7 working groups and HL7 FHIR Connectathons to help advance the maturity and adoption of FHIR domestically and internationally.


Review our terms of use and documentation to begin developing your FHIR integration.


When you register your developer account, accept the User Agreement and provide a valid email address. You’ll receive credentials that you can use to register your applications. If you have questions, reach out to VeradigmConnect@veradigm.com.


Note: The FHIR documentation on this portal applies to the Veradigm and Altera FHIR APIs. For information on Paragon Open API, go here.


Functionality Considerations

The Veradigm and Altera FHIR API is limited to read-only access and not write-backs. For application developers seeking deeper integration with Veradigm and Altera EHRs, Veradigm Connect offers the bidirectional Unity API, enabling both reads and writes. To integrate with Veradigm Practice Management, developers must utilize Unity to read or write patient demographic, appointment, or financial data.


Single Sign-On (SSO) for FHIR R4 is not yet supported within Sunrise and Paragon EHRs. Veradigm EHR version 24.5 or later supports SSO. For app launch capabilities, developers are advised to leverage Unity for earlier versions of Veradigm EHR and Sunrise.


For more information, contact VeradigmConnect@veradigm.com.


Developer Portal Sign-up

Sign up at https://developer.veradigm.com/ to get access to Veradigm and Altera FHIR-enabled APIs and start testing in our sandboxes.

  1. Click Sign Up.
  2. Complete the required information.
  3. Review the user agreement.
  4. Confirm you are not a robot.
  5. Click I Accept.

Register FHIR Application

Register your FHIR application to connect to clients and begin testing.

  1. On the Veradigm Developer Program portal, go to the My Dashboard page.
  2. On the My FHIR Applications tile, click + to a new application. Note: If there is already a version of the application for DSTU2, you do not need to create a new application.
  3. On the FHIR App page, complete the following information:
    • App Name: Indicates the application name. Enter an App Name that clearly identifies your company and product. This name will appear in our client's License Management Portal where clients will elect to license your application.
    • App Type: Indicates the primary audience for the application. Select Patient, Provider, or System. The App type impacts how the client views your application within the License Management Portal. It is important to identify the app type accurately.
      • Patient: The app's intended audience is patients.
      • Provider: The app's intended audience is physicians and healthcare providers.
      • System: The app's intended audience is an external system, not a physician or provider. For example, an insurance company.
    • App Description: Indicates a detailed description of how and why the application is used.
    • Additional info link: Indicates a link to more information on the application. For example, the partner's marketing website. Both the App Description and the Additional info link will display in the client License Management Portal to help identify the application to EHR organizations when authorizing applications.
    • JWKS URL: Indicates the URL for backend authentication access (JWKS) tokens. It is expected that a SMART on FHIR application developer can stand up a JWKS endpoint for their public key. That way, the application developer can recycle the keys when necessary, without having to contact all the FHIR API vendors they communicate with.
    • Redirect URLs: Indicates up to five redirect URLs. Include redirect_uri urn:ietf:wg:oauth:2.0:oob for desktop applications; if you are developing a web client, use a URL pointing back to your website. For example, https://yourdomain.com/callback.
    • Launch URLs: Indicates the URL used to launch a SMART on FHIR application. Enter up to three values.
    • Client Type: Indicates if this is a Confidential Client (trusted) or a Public Client (not trusted).
    • App Type: Indicates if this is a Native App (desktop) or a Web App (mobile).
  4. There is no need to indicate if this is a test or production application under Licensing Information. Once clients have licensed the application, the portal displays a list of organizations that have authorized the R4 application to connect to their environments.
  5. For R4 applications, check the scopes that are required for the application to function as intended. Once production access has been granted, these scopes become the default scope values for the application in the License Management Portal. Do not request scopes that don't correspond to your app type and aren't necessary for the application to function. For example, if you have a patient application that works with medications, don't request scopes that begin with user/. If the application will require a refresh token, check offline_access. Note: A client may still deny access to certain scopes when they authorize an application in the License Management Portal.
  6. Click Save. The portal generates and displays the following information, collectively referred to as OAuth/FHIR Credentials:
    • Client ID
    • Secret
    • Secret Expiration Date
  7. Click OK.

The application has been registered. However, before it can be activated for a client, the developer needs to perform the following additional steps:

  1. On the FHIR App page, select a Purpose of Use for the application. Purpose of Use definitions are available from that page.
  2. Select the appropriate scopes for the application. Scopes control the type of information the application is requesting from the EHR. The scopes must match the FHIR app type. For example, scopes that begin patient/ are for use with patient applications. Never request scopes that are not required for the application to function.
  3. Once testing is complete, the developer can request production access for the application by clicking Request Production Access on the FHIR App page.

Important: Do not request production access for the application until the application name, type, and Purpose of Use are finalized and the application is fully tested. These values cannot be changed once production access is granted.


The FHIR application is reviewed and, if appropriate, approved by Veradigm Connect. Once approved, clients can begin activating the FHIR application.


Client Licensing

Clients use a separate portal for licensing and managing FHIR applications linked to their organization. Veradigm Connect developers cannot license their applications for clients; the clients must activate applications themselves through the License Management Portal (LMP). If a client requests guidance from a FHIR application developer, you can provide them the following link to documentation: License Management Portal documentation.

Note that developers do not have access to this documentation site. Clients must use their Veradigm or Altera Client Portal credentials to access this information.


Licensing Information

On the FHIR App page, the Licensing Information section was expanded to include both FHIR R2 (DSTU2) and R4 applications. Applications that use the Veradigm and Altera FHIR R4 API must be explicitly licensed for individual client sites. The list of previously configured client sites for the selected application displays.


Testing

For information about testing credentials, go to the Partner Testing Environments page.

You can use most API test utilities to test your FHIR application. The Veradigm and Altera FHIR API teams uses Postman to test Patient and User type FHIR applications. Custom utilities can be created to test System type FHIR applications.

Patient and User Applications

Patient and User type FHIR applications authenticate by entering user credentials for the Veradigm or Altera EHR or patient portal (such as AHC or FollowMyHealth). Postman can send requests to these systems to obtain these tokens.

Before attempting to send FHIR requests to the Veradigm or Altera EHR, it is helpful to create an environment file with the following variables.

  • FhirURL: FHIR server URL.
  • AuthURL: FHIR authorization server URL. This often ends in …/authorize. The authorization server validates that the application has been authorized, and then validates the user’s credentials. You can obtain the AuthURL by calling the Capability Statement.
  • CallbackURL: Callback URL. This is where the authorization sends a temporary token to application. For example, http://localhost/callback.
  • TokenURL: FHIR Token server URL. This often ends in …/token. The application sends the temporary to the TokenURL and a regular token is returned. You can obtain the TokenURL by calling the Capability Statement.
  • ClientID: FHIR application Client ID. This is found on the FHIR App page in the Veradigm Connect portal.
  • ClientSecret: FHIR application Client Secret. This is found on the FHIR App page in the Veradigm Connect portal.
  • Scope: FHIR application scope. This is requested by the FHIR application developer on the FHIR App page in the Veradigm Connect portal.

To create an environment in Postman:

  1. Create or go to your workspace.
  2. Click Environments, and then click New.
  3. On the Create New screen, click Environment.
  4. Enter the variables, and then click Save.

Next, create a request.

  1. Click New.
  2. On the Create New screen, click HTTP Request.

Next, obtain a token.

  1. On the request’s tab, click the Authorization tab.
  2. In Type, select OAuth 2.0.
  3. In Header Prefix, select Bearer.
  4. Under Configure New Token, refer to the variables you created in your Environment file by using the {{variable name}}. For example, for Auth URL, enter {{AuthURL}}.
  5. Click Get New Access Token.
  6. For a User application, the Veradigm or Altera EHR log in screen displays. Enter the EHR credentials. For a Patient application, enter the patient’s portal credentials.
  7. Postman displays the token. Click Use Token.

You can now enter an HTTP request and click Send.

Note: Tokens expire after a set amount of time configured by the client. You will need to generate new tokens periodically.

For more information on Postman, see the Postman Support Center or Learning Center.

System Applications

Instead of entering product credentials to obtain a token, System applications make a direct call to the Token URL. The body of the request must include the following:

  • client_assertion: Indicates a token generated using a private key. The key must be signed by a certificate authority. There is no way to generate this token in Postman, and thus it must be generated by another utility. Sample code for creating your own utility follows.
  • client_assertion_type: urn:ietf;params;oauth:client-assertion-type:jwt-bearer
  • grant_type: client_credentials
  • scope: system/*.read

C# Sample Code for Generating Access Token with System Application

private async Task GetBearerToken()

{

    string accessToken = null;

    string tokenURL = "[token URL of FHIR auth server]";

    string clientID = "[your FHIR app client ID]";

    var tokenCode = GenerateJWT(tokenURL, clientID);

    var address = new Uri(tokenURL);

    using (var handler = new HttpClientHandler())

    {

        handler.UseCookies = false;

        using (var client = new HttpClient(handler))

        {

            var message = new HttpRequestMessage(HttpMethod.Post, address);

            var content = new FormUrlEncodedContent(new[]

            {

                    new KeyValuePair("scope", "system/*.read"),

                    new KeyValuePair("grant_type", "client_credentials"),

                    new KeyValuePair("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),

                    new KeyValuePair("client_assertion", tokenCode),

                });

            message.Content = content;

            var httpResponse = await client.SendAsync(message);

            var result = await httpResponse.Content.ReadAsStringAsync();

            if (httpResponse.IsSuccessStatusCode)

            {

                var tokenResponse = JObject.Parse(result);

                accessToken = tokenResponse.SelectToken("access_token").Value();

            }

        }

    }

    return accessToken;

}

private string GenerateJWT(string authServerTokenURL, string clientID)

{

    X509Store store = new X509Store(StoreLocation.LocalMachine);

    store.Open(OpenFlags.ReadOnly);

    X509Certificate2 signingCert = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false)[0];

    var jti = CryptoRandom.CreateUniqueId(32);

    List claims = new List()

        {

            new Claim("sub", clientID),

            new Claim("jti", jti),

        };

    var tokenHandler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();

    var tokenDescriptor = new SecurityTokenDescriptor

    {

        Subject = new ClaimsIdentity(claims),

        Issuer = clientID,

        Audience = authServerTokenURL,

        Expires = DateTime.UtcNow.AddMinutes(5),

        SigningCredentials = new X509SigningCredentials(signingCert)

    };

    var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);

    var tokenString = tokenHandler.WriteToken(token);

    return tokenString;

}