Importing / Adding Providers

How to add new providers and update their data

Overview

Importing Providers to Medallion Platform is a multi-step process:

  1. Create a Membership for each Provider with the appropriate role
  2. [Optional] Send an Invitation to each Provider to join the Platform themselves
  3. Update the Provider's basic information (name, age, gender, NPI number, etc.)
  4. Add other objects related to that Provider (e.g., their documents, existing licenses, existing enrollments)

Creating Memberships

Each of your Providers must have a Membership in your Organization, so we begin by creating a Membership for each Provider with the Organization Membership endpoint. Start by setting your API key, then gather your Provider's emails & professions, then create a membership for each one.

📘

Save your IDs!

Make sure to save the provider ID returned along with each Membership! You'll need this in the next step!

If at any point you lost track of your Provider IDs, you can use the GET Providers endpoint with a search to find them again, e.g. with requests.get(providers_url, params={"search": "[email protected]"}, headers=headers).

import requests

api_key = "<YOUR_API_KEY>"
organization_id = "<YOUR_ORG_ID>"
base_url = "https://api.medallion.co"

headers = {"x-api-key": api_key, "accept": "application/json"}

membership_url = f"{base_url}/p/api/v1/organizations/members/"

# Placeholder provider data.  In practice, this will probably be loaded from a spreadsheet or other source.
provider_data = [
    {
        "email": "[email protected]",
        "profession": "MD",
        "first_name": "Jane",
        "last_name": "Doe",
    },
    {"email": "[email protected]", "profession": "DO", "first_name": "Cher"},
]

# Iterate over providers, create a membership for each, and store the provider ID
for provider in provider_data:
    response = requests.post(
        membership_url,
        json={
            "role": "provider",
            "user": {"email": provider["email"]},
            "provider": {"profession": provider["profession"]},
        },
        headers=headers,
    )
    response.raise_for_status()
    response_json = response.json()
    provider["provider_id"] = response_json["provider"]["id"]
    provider["membership_id"] = response_json["id"]

👍

More information about Memberships

For more information about how to manage Memberships via the Medallion API, please see Managing User Memberships.

[Optional] Sending invitations

This is an entirely optional step, but if you'd like your Providers to also have access to the Medallion Platform, you'll need to explicitly trigger an emailed invitation. To do so, send a POST request to the Organization Invite endpoint for each Member that you'd like to invite:

invites_url = f"{base_url}/p/api/v1/organizations/{organization_id}/invites/"

# Iterate over the provider data again and send an invitation to each provider
# Could be done in the same loop as above, but split out here for readability
for provider in provider_data:
    response = requests.post(
        invites_url, json={"membership_id": provider["membership_id"]}, headers=headers
    )
    response.raise_for_status()

Updating Provider data

Now that you've created your Memberships, it's time to update your Providers' data. For data that lives on the Provider itself (e.g. their name, their NPI or CAQH number, their Medicare PTAN or Medicaid ID, whether they're a US citizen, and so on) can be updated by sending a PATCH request for each Provider to PATCH a Provider -- see that endpoint's Body Parameters for a full list of fields that can be directly updated.

def get_provider_url(provider_id):
    return f"{base_url}/api/v1/org/providers/{provider_id}/"


# Again, the following loop could be rolled into the first one
for provider in provider_data:
    response = requests.patch(
        get_provider_url(provider["provider_id"]),
        json={
            key: val
            for key, val in provider.items()
            if key not in {"email", "membership_id", "provider_id"}
        },
        headers=headers,
    )
    response.raise_for_status()

Next steps

You've now created Memberships for your Providers, optionally sent them Invitations to manage their own data, and imported their basic information -- you're already well on your way to success!

However, there are more steps that you can take, if you have additional data you'd like to import. You might want to add exams that your Providers have taken; import licenses that they already have; fill out their education, training, and work experience, upload documents to their profile, and so on.

The input data for each of these endpoints will vary slightly, but the general process will remain the same for each -- for each Provider, send a POST request to the appropriate endpoint for each related object that you want to create.

We'll highlight a few examples for completeness sake.

Adding an Exam

def get_exams_url(provider_id):
    return f"{get_provider_url(provider_id)}exams/"


# mock data
exams_by_provider_email = {
    "[email protected]": [
        {
            "exam_type": "pance",
            "has_passed": True,
            "attempts_count": 2,
            "exam_date": "2023-02-14",
        },
        {"exam_type": "nclex", "has_passed": False, "attempts_count": 1},
    ]
}

for provider in provider_data:
    url = get_exams_url(provider["provider_id"])
    for exam in exams_by_provider_email.get(provider["email"], []):
        response = requests.post(url, json=exam, headers=headers)
        response.raise_for_status()
        exam["exam_id"] = response.json()["id"]

Adding a License

licenses_url = f"{base_url}/api/v1/org/licenses/"

# mock data
licenses_by_provider_email = {
    "[email protected]": [
        {"state": "CA", "status": "active", "license_number": "123456"},
        {"state": "OR", "status": "inactive", "license_number": "98765"},
    ],
}

for provider in provider_data:
    for license in licenses_by_provider_email.get(provider["email"], []):
        response = requests.post(
            licenses_url,
            json={"provider": provider["provider_id"], **license},
            headers=headers,
        )
        response.raise_for_status()
        license["license_id"] = response.json()["id"]

Adding Documents

Documents are unique in that they require uploading files. For more details on Documents in general, see Working with Documents.

def get_document_upload_url(provider_id):
    return f"{base_url}/api/v1/org/providers/{provider_id}/documents/"


# mock data
documents_by_provider_email = {
    "[email protected]": [
        {"path": "email1-passport.png", "title": "Latest Passport", "kind": "passport"},
        {"path": "email1-resume.pdf", "title": "Latest Resume", "kind": "cv"},
    ],
    "[email protected]": [
        {"path": "email2-drivers-license.jpg", "title": "DL", "kind": "drivers_license"}
    ]
}

for provider in provider_data:
    url = get_document_upload_url(provider['provider_id'])
    for document in documents_by_provider_email.get(provider['email'], []):
        with open(document['path'], 'rb') as f:
            response = requests.post(
                url,
                data={"title": document['title'], 'kind': document['kind']},
                files=[("content", f)],
                headers=headers,
            )
            response.raise_for_status()

Code roundup

The following script summarizes all of the code blocks above:

import requests

api_key = "<YOUR_API_KEY>"
organization_id = "<YOUR_ORG_ID>"
base_url = "https://api.medallion.co"

headers = {"x-api-key": api_key, "accept": "application/json"}

membership_url = f"{base_url}/p/api/v1/organizations/members/"

# Placeholder provider data.  In practice, this will probably be loaded from a spreadsheet or other source.
provider_data = [
    {
        "email": "[email protected]",
        "profession": "MD",
        "first_name": "Jane",
        "last_name": "Doe",
    },
    {"email": "[email protected]", "profession": "DO", "first_name": "Cher"},
]

# Iterate over providers, create a membership for each, and store the provider ID
for provider in provider_data:
    response = requests.post(
        membership_url,
        json={
            "role": "provider",
            "user": {"email": provider["email"]},
            "provider": {"profession": provider["profession"]},
        },
        headers=headers,
    )
    response.raise_for_status()
    response_json = response.json()
    provider["provider_id"] = response_json["provider"]["id"]
    provider["membership_id"] = response_json["id"]

invites_url = f"{base_url}/p/api/v1/organizations/{organization_id}/invites/"

# Iterate over the provider data again and send an invitation to each provider
# Could be done in the same loop as above, but split out here for readability
for provider in provider_data:
    response = requests.post(
        invites_url, json={"membership_id": provider["membership_id"]}, headers=headers
    )
    response.raise_for_status()


def get_provider_url(provider_id):
    return f"{base_url}/api/v1/org/providers/{provider_id}/"


# Again, the following loop could be rolled into the first one
for provider in provider_data:
    response = requests.patch(
        get_provider_url(provider["provider_id"]),
        json={
            key: val
            for key, val in provider.items()
            if key not in {"email", "membership_id", "provider_id"}
        },
        headers=headers,
    )
    response.raise_for_status()


def get_exams_url(provider_id):
    return f"{get_provider_url(provider_id)}exams/"


# mock data
exams_by_provider_email = {
    "[email protected]": [
        {
            "exam_type": "pance",
            "has_passed": True,
            "attempts_count": 2,
            "exam_date": "2023-02-14",
        },
        {"exam_type": "nclex", "has_passed": False, "attempts_count": 1},
    ]
}

for provider in provider_data:
    url = get_exams_url(provider["provider_id"])
    for exam in exams_by_provider_email.get(provider["email"], []):
        response = requests.post(url, json=exam, headers=headers)
        response.raise_for_status()
        exam["exam_id"] = response.json()["id"]


licenses_url = f"{base_url}/api/v1/org/licenses/"

# mock data
licenses_by_provider_email = {
    "[email protected]": [
        {"state": "CA", "status": "active", "license_number": "123456"},
        {"state": "OR", "status": "inactive", "license_number": "98765"},
    ],
}

for provider in provider_data:
    for license in licenses_by_provider_email.get(provider["email"], []):
        response = requests.post(
            licenses_url,
            json={"provider": provider["provider_id"], **license},
            headers=headers,
        )
        response.raise_for_status()
        license["license_id"] = response.json()["id"]


def get_document_upload_url(provider_id):
    return f"{base_url}/api/v1/org/providers/{provider_id}/documents/"


# mock data
documents_by_provider_email = {
    "[email protected]": [
        {"path": "email1-passport.png", "title": "Latest Passport", "kind": "passport"},
        {"path": "email1-resume.pdf", "title": "Latest Resume", "kind": "cv"},
    ],
    "[email protected]": [
        {"path": "email2-drivers-license.jpg", "title": "DL", "kind": "drivers_license"}
    ]
}

for provider in provider_data:
    url = get_document_upload_url(provider['provider_id'])
    for document in documents_by_provider_email.get(provider['email'], []):
        with open(document['path'], 'rb') as f:
            response = requests.post(
                url,
                data={"title": document['title'], 'kind': document['kind']},
                files=[("content", f)],
            )
            response.raise_for_status()