Developer Guide

From NoMoreClipboard
Jump to: navigation, search

Forward

Copyright Notice

This Publication is copyrighted by NoMoreClipboard, Inc. (NMC) and is therefore protected by the Copyright Laws of the United States and copyright provisions of various international treaties. The effect of such laws and treaties is that you may not, without license, copy or distribute this publication. NoMoreClipboard.com members are authorized to reproduce the publication for internal use in their organizations.

Introduction

Audience

This document is intended for developers looking to recieve or send data to NoMoreClipboard.com into personal health records. This document outlines the necessary steps to begin integration.

NOTE: NoMoreClipboard.com does NOT currently have an "open enrollment" to our API. We only grant API access to pre-qualified 3rd party partners with NoMoreClipboard.com. If your organization has an interest in partnering with NoMoreClipboard.com, please contact us directly at bizdev@nomoreclipboard.com.

Definitions

These definitions are used throughout this document. While the terms defined here may have several competing meaning and may not be fully defined in the medical community, special care has been taken to use these definitions throughout this document.

  • CDA - Clinical Document Architecture – HL7
  • CCD - Continuity of Care Document – HL7
  • CCR - Continuity of Care Record
  • EHR - Electronic Health Record
  • EMR - Electronic Medical Record
  • PHR - Personal Health Record
  • NMC - NoMoreClipboard.com
  • NMC Member - A member is a patient/indiviudal. There are more than one NMC Member per account and may even be shared between multiple accounts.
  • NMC Account - An account is a user who logs into NMC and manages multiple NMC members.
  • NPI - National Provider Identifier (https://nppes.cms.hhs.gov/NPPES/Welcome.do)

Messaging/Interface Overview

Applications exchange information with NoMoreClipboard.com as messages. Several encoding formats are understood including (CDA/CCD, CCR, HL7 v2.x, ANSI 837, ANSI 270)

There are two basic methods of

  • Push
  • Pull (aka: Query)

The advantage of the push method is real time transmission of transactions as they happen, but this requires that the receiving application be accessible through any firewalls. NoMoreClipboard.com can provide an IP address range to help lock down the service, but the IP addresses are subject to change.

Message Diagram

Blended Scanerios

Prerequisite Setup

  • Register your organization’s globally unique Assigning Facility ISO identifier with NMC
    • If you do not have one, NMC can assign one.
  • Register a NPI for each provider with NMC (This is only necessary if you are trying to send/receive documents for physicians or physician offices).
    • If you do not have an NPI you can follow the instructions below to get one, or if unable to get one from NPPES, NMC can assign one for just NoMoreClipboard.com.
  • Decide on the transport for NMC to deliver messages to your application.

Assigning Facility ISO Identifier

Every system (assigning facility) that assigns a patient identifier (medical record number) needs to have a globally unique ID in the ISO format. For example, if there is a billing system that assigns an account number and an EMR that assigns a medical record number, then there would be two assigning facilities. Therefore there would be two assigning facility ID in the ISO format. If your organization does not have an ISO number, NoMoreClipboard.com can assign one for you. For example, NoMoreClipboard.com's assigning facility idendifier is 1.2.840.114398.1.35.1.

National Provider Identifier (NPI)

The Administrative Simplification provisions of the Health Insurance Portability and Accountability Act of 1996 (HIPAA) mandated the adoption of a standard unique identifier for health care providers. The National Plan and Provider Enumeration System (NPPES) collects identifying information on health care providers and assigns each a unique National Provider Identifier (NPI).

For each provider that receives or sends information through NoMoreClipboard.com needs to have a National Provider ID

Sandbox NoMoreClipboard.com

To aid in development, NoMoreClipboard.com offers a developer sandbox systems. You can request a sandbox system by contacting NMC.

Sending messages to NoMoreClipboard.com

Before beginning to test with your sandbox, or use live with nomoreclipboard.com, you will need the following:

  • A partition code assigned to your organization by NoMoreClipboard in the system you are sending to.
  • A username and password to submit messages

Sandbox system: https://sandbox.nomoreclipboard.com/YOURHANDLE/nmc.cgi Live system: https://nomoreclipboard.com/nmc.cgi

Posting CGI Attributes
Attribute Description Value Type (O=Optional, R=Required, Rv=Required to be the value listed) Sample or Required Values
f Tells NMC you are requesting to do a document upload. Rv chart
s Tells NMC you are requesting to do a document upload. Rv upload
partition Partition code. This value along with the mrnumber attribute specify the account you are trying post to. O XYZ
mrnumber The mrnumber of the account you are trying to post to. This consists of the partition code assigned to you by NMC, a dash, and then your systems internal id of the person you are trying to upload a document for. If you would like us to assign an ISO number to the partition, you then may also use that instead of the partition name. The hyphen and partition code is optional in this field if it is provided by the partition attribute. R XYZ-12345 or 12345
storage_type Internal storage type code that tells NMC you are trying to upload an XML type of formatted file. 19 = CCD/CDA, 21=CCR (Other storage types: 1 = Text, 3 = PNG, 4 = HTML, 6 = Word Document, 8 = JPEG) R (If XML) 21
service_date Date that the document was created O 2010-05-10 12:22:00
register_patient Flag which tells NMC that you want NMC to create a new patient if one does not already exist with your MR number. O 1
register_promo Flag which tells NMC that you want NMC to return back to you a 'pickup code' that the member may use to retrieve their patient within their NMC account. O 1
register_autofroo Flag which tells NMC that you want NMC to automatically reconcile (Froozhie) the data where applicable into the patients account. The patient does have to have a record agreeing to auto reconcile with one of the providers in your Provider Organization within the NMC system as well for the auto reconcile to happen. O 1
skip_cur_enc_link Flag which tells NMC that you want NMC to skip creating an encounter link from the patient's current encounter to the document being uploaded. O 1
doc_type This tells NMC what type of document is being uploaded. Supported types for XML documents are WCCCR=CCR, WCCDA=CDA/CCD document. If you are trying to upload another type of document, please contact NoMoreClipboard, and we can suggest a document type to use, based on the file being uploaded. R WCCCR
subject This is a subject line that can be used to describe the document being uploaded. This will display in the patients document list. O Update from Doctor
file This should be the text that you want uploaded to the account, or the attached file that you want to upload. When attaching a file, include the Content-Type. R File text (or attached file to post)
login_user Username if not certificate based R
login_passwd Password if not certificate based R
Sample .NET 4.0 Application
 docuploaddotnet4.exe MIE-10019 WCCHECKOUT 1 2015-5-2 OFFICE username password 0 testing.txt "https://url/webchart.cgi"
 
 Uploading testing.txt to https://url/webchart.cgi
 File uploaded, server response is: <Response><System><OID>1.2.840.114398.1.668.11999116119114101105115107101</OID>
 </System>
 <ErrorCode>2048</ErrorCode>
 <Text>Document (0000492) Uploaded Successfully!</Text>
 <DocumentID>492</DocumentID>
 <Codes><Type>MIE</Type>
 <Value>10019</Value>
 
 </Codes>
 </Response>
   using System;
   using System.Collections.Generic;
   using System.Collections.Specialized;
   using System.IO;
   using System.Linq;
   using System.Net;
   using System.Text;
   namespace docuploaddotnet4
   {
       class Program
       {
           public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc)
           {
               Console.WriteLine(string.Format("Uploading {0} to {1}", file, url));
               string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
               byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
 
               HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
               wr.ContentType = "multipart/form-data; boundary=" + boundary;
               wr.Method = "POST";
               wr.KeepAlive = true;
               wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
   
               Stream rs = wr.GetRequestStream();
   
               string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
               foreach (string key in nvc.Keys)
               {
                   rs.Write(boundarybytes, 0, boundarybytes.Length);
                   string formitem = string.Format(formdataTemplate, key, nvc[key]);
                   byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                   rs.Write(formitembytes, 0, formitembytes.Length);
               }
               rs.Write(boundarybytes, 0, boundarybytes.Length);
    
               string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
               string header = string.Format(headerTemplate, paramName, file, contentType);
               byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
               rs.Write(headerbytes, 0, headerbytes.Length);
   
               FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
               byte[] buffer = new byte[4096];
               int bytesRead = 0;
               while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
               {
                   rs.Write(buffer, 0, bytesRead);
               }
               fileStream.Close();
   
               byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
               rs.Write(trailer, 0, trailer.Length);
               rs.Close();
   
               WebResponse wresp = null;
               try
               {
                   wresp = wr.GetResponse();
                   Stream stream2 = wresp.GetResponseStream();
                   StreamReader reader2 = new StreamReader(stream2);
                   Console.WriteLine(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
               }
               catch (Exception ex)
               {
                   Console.WriteLine("Error uploading file", ex);
                   if (wresp != null)
                   {
                       wresp.Close();
                       wresp = null;
                   }
               }
               finally
               {
                   wr = null;
               }
           }
           static int Main(string[] args)
           {
               if (args.Length != 10)
               {
                   Console.WriteLine("Incorrect Usage!");
                   Console.WriteLine("docuploadexample.exe mrnumber doc_type storage_type service_date service_location login_user login_passwd doc_interface file url");
                   return 0;
               }
               string mrnumber = args[0];
               string doc_type = args[1];
               string storage_type = args[2];
               string service_date = args[3];
               string service_location = args[4];
               string login_user = args[5];
               string login_passwd = args[6];
               string doc_interface = args[7];
               string file = args[8];
               string url = args[9];
   
               NameValueCollection data = new NameValueCollection();
               data["f"] = "chart";
               data["s"] = "upload";
               data["obopp"] = "add";
               data["mrnumber"] = mrnumber;
               data["doc_type"] = doc_type;
               data["storage_type"] = storage_type;
               data["service_date"] = service_date;
               data["service_location"] = service_location;
               data["login_user"] = login_user;
               data["login_passwd"] = login_passwd;
               data["doc_interface"] = doc_interface;
 
               HttpUploadFile(url, file, "file", "application/octet-stream", data);
               return 0;
           }
       }
   }
Sample .NET 4.5 Application
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace docuploadexample
{
    class Program
    {
        static int Main(string[] args)
        {
            if (args.Length != 10)
            {
                Console.WriteLine("Incorrect Usage!");
                Console.WriteLine("docuploadexample.exe mrnumber doc_type storage_type service_date service_location login_user login_passwd doc_interface file url");
                return 0;
            }
            string mrnumber = args[0];
            string doc_type = args[1];
            string storage_type = args[2];
            string service_date = args[3];
            string service_location = args[4];
            string login_user = args[5];
            string login_passwd = args[6];
            string doc_interface = args[7];
            string file = args[8];
            string url = args[9];

            Console.WriteLine(url);

            // Convert each of the three inputs into HttpContent objects
 
            HttpContent stringContent = new StringContent(file);
            // examples of converting both Stream and byte [] to HttpContent objects
            // representing input type file
            HttpContent fileStreamContent = new StreamContent(File.OpenRead(file));
 
            // Submit the form using HttpClient and 
            // create form data as Multipart (enctype="multipart/form-data")
 
            using (var client = new HttpClient())
            using (var formData = new MultipartFormDataContent())
            {
                // Add the HttpContent objects to the form data

                var data = new NameValueCollection();
                data["f"] = "chart";
                data["s"] = "upload";
                data["obopp"] = "add";
                data["mrnumber"] = mrnumber;
                data["doc_type"] = doc_type;
                data["storage_type"] = storage_type;
                data["service_date"] = service_date;
                data["service_location"] = service_location;
                data["login_user"] = login_user;
                data["login_passwd"] = login_passwd;
                data["doc_interface"] = doc_interface;
                data["file"] = file;
 
                foreach (string key in data)
                {
                    var value = data[key];
                    formData.Add(new StringContent (value), key);
                    Console.WriteLine("Key: " + key + " - Value: " + value);
                }

                formData.Add(fileStreamContent, "file", "file");

                // Actually invoke the request to the server

                // equivalent to (action="{url}" method="post")
                var response = client.PostAsync(url, formData).Result;

                // equivalent of pressing the submit button on the form
                if (!response.IsSuccessStatusCode)
                {
                    return 0;
                }
                response.Content.ReadAsStreamAsync().Result.Position = 0;
                var sr = new StreamReader(response.Content.ReadAsStreamAsync().Result);
                var myStr = sr.ReadToEnd();
                Console.WriteLine(myStr);
                return 0;
            }
        }
    }
}
Sample Bash Script
#!/bin/bash

if  $# -lt 10 ; then
	echo Usage: $0 mrnumber doctype stgtype content_type servdate sevloc user password file url
	exit 1
fi

INTERFACE=$0
MRNUMBER=$1
DOCTYPE=$2
STGTYPE=$3
CONTENTTYPE=$4
SERVDATE=$5
SERVLOC=$6
LOGINUSER=$7
LOGINPASS=$8
FILE=$9
URL=$10

curl -i \
-F "f=chart" \
-F "s=upload" \
-F "mrnumber=$MRNUMBER" \
-F "doc_type=$DOCTYPE" \
-F "storage_type=$STGTYPE" \
-F "service_date=$SERVDATE" \
-F "service_location=$SERVLOC" \
-F "login_user=$LOGINUSER" \
-F "login_passwd=$LOGINPASS" \
-F "doc_interface=$INTERFACE" \
-F "file=@$FILE;type=$CONTENTTYPE" \
"$URL"
XML Returned
   <Response>
       <System>
           <OID>1.2.840.114398.1.35.1</OID>
       </System>
       <ErrorCode>2048</ErrorCode>
       <Text>Document (0001908) Uploaded Successfully!</Text>
       <DocumentID>1908</DocumentID>
       <Codes>
           <Code>
               <Type>NMC</Type>
               <Value>9029</Value>
           </Code>
           <Code>
               <Type>PICKUP</Type>
               <Value>DGF8D8GGF7GF</Value>
           </Code>
       </Codes>
   </Response>

System OIDs:

  • 1.2.840.114398.1.35.1 - NMC Live OID

Error Codes:

  • 2048 - Successful transmission

Text: Lists textual version of error/success message

DocumentID: Our internal Document ID

Codes: XML listing of Medical Record codes in our system. One should be the code type assigned to your system, others might be the NMC code, or the PICKUP code.

Getting/Receiving messaging from NoMoreClipboard.com

All of the transports require 128-bit or greater TLS/SSL (Transport Layer Security/Secure Sockets Layer). The protocols allow client/server applications to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery.

Transports

TLS 1.0 documents may be found at http://www.ietf.org/rfc/rfc2246.txt SSL 3.0 documents may be found at http://wp.netscape.com/eng/ssl3/

If existing applications lack support for TLS/SSL, we highly recommend Stunnel for an open source solution to enable encryption. Stunnel has both a Win32 version and a Unix version. It is also possible to run Stunnel on a different server than the server that need to communicate with NoMoreClipboard.com.

There are two basic methods to establish communication with NoMoreClipboard.com. In situations where your system is behind a firewall that prevents incoming connections, you will want to choose the mode where NoMoreClipboard.com waits for your service (Query) to connect and pull information. In situations where you want near real time exchange of messages, you will want to open up a port for NoMoreClipboard.com to connect to your server.

NoMoreClipboard waits for incoming connections (Query)

Inboxflow.jpg


CCR Format

NoMoreClipboard CCR Data Elements

Single Sign On

NoMoreClipboard.com can participate in single sign-on schemes including OpenID, SAML, and Shibboleth. For some of the schemes, NoMoreClipboard.com can act is the identity source, while in most cases, NoMoreClipboard.com is the identity consumer.

NoMoreClipboard.com acts as the Identity Consumer

Each of the following protocols can be used to authenicate a user to log into their NoMoreClipboard.com account:

Special URLs are provided on a case-by-case basis to enable the single sign on process. In most cases, the URLs are put on an intranet page or partnering website to allow their user to log in. It is possbile to configure the creation of accounts dynamically for users that authenticate but do not have accounts. Contact NoMoreClipboard.com for more information on the setup.

NoMoreClipboard.com acts as the Identity Provider

Widgets in the NoMoreClipboard.com summary page can launch an external system with OpenID SSO capability. NoMoreClipboard.com will create a URL to direct a user to the external system with OpenID tokens. The receiving system must verify the assertion that is created by NoMoreClipboard.com by verifying the signature.

NMC does not currently support Direct Verification.

For more information: