Skip to main content

BoreDM

BoreDM is a cloud-based geotechnical data management platform that enables organizations to store, manage, and visualize borehole log data, lab test results, and geotechnical site investigation information. The VIKTOR integration allows you to access BoreDM project data, boring logs, lithology, samples, and lab results through the BoreDM REST API.

Prerequisites
  • You have access to a BoreDM account with API access
  • You have a BoreDM API key (request one from boredm.com)

BoreDM API structure

This guide walks you through integrating BoreDM with VIKTOR, starting with provisioning an API key from your BoreDM account, securing it as an environment variable, and then using the BoreDM REST API to access your geotechnical data.

In this guide we will cover the following endpoints:

  • Projects (/api/v4/project/) - List and access BoreDM projects visible to your API key
  • Working with log data (/api/v4/project/{project_id}/geojson) - Retrieve borehole locations and log IDs
  • Lithology (/api/v4/logs/{project_id}/lithology) - Access soil layer descriptions, depths, and classifications
  • Samples (/api/v4/logs/{project_id}/sample) - Retrieve SPT N-values, blow counts, sample depths, and recovery data
  • Specimens (/api/v4/logs/{project_id}/specimen) - Access lab test results linked to field samples
  • Other tables (/api/v4/logs/{project_id}/{table}) - Query generic/custom tables, teams, users, and project-level data

Getting a BoreDM API key

To use the BoreDM API, you need to provision an API key from your BoreDM account. Follow these steps:

  1. Navigate to Teams - In the BoreDM sidebar, click on Teams under the Resources section
  2. Open the Organization tab - Click on the Organization tab at the top of the page
  3. Provision a new API key - Select a user, enter a key name, and click + Provision new API key

BoreDM API key provisioning interface

Environment variables and secrets

Once you have your BoreDM API key, you need to link it to your VIKTOR app. The API key should be stored as the environment variable BOREDM_API_KEY.

Whether you are working in the App Builder or in local development, follow the appropriate setup below. For more details on environment variables, see the App Builder environment variables guide or the local development environment variables guide.

  • Open the app in the App Builder.
  • Click the gear icon in the bottom-left corner.
  • Open the Variables tab.
  • Add a variable named BOREDM_API_KEY.
  • Mark it as secret when storing a real BoreDM API key.
  • Read it in Python with os.environ["BOREDM_API_KEY"].
  • Use the same name in all snippets on this page.
import os

api_key = os.environ["BOREDM_API_KEY"]

For more details on environment variables, see the App Builder environment variables guide or the local development environment variables guide.

warning

Do not put the BoreDM API key in a VIKTOR field, browser-side JavaScript, Plotly figure metadata, or a printed log message.

Authentication

Every BoreDM request needs the same base URL and authorization header. This section defines the minimum request contract used by all code examples on this page.

  • Base URL: https://boredm.com
  • API version prefix: /api/v4
  • Required header: Authorization: Secret <BOREDM_API_KEY>
  • Best practices:
    • Store the API key in environment variables (see section above)
    • Read it with os.environ["BOREDM_API_KEY"]
    • Keep the key server-side in Python
    • Never expose the key in browser-side JavaScript or client-visible code

BoreDM Projects

Project endpoints are the normal entry point for a VIKTOR integration because every log and table request needs a selected project ID.

Endpoint: GET /api/v4/project/

Use this endpoint to discover which BoreDM projects the current API key can read.

Use it to:

  • List projects visible to the API key
  • Fill a VIKTOR project selector
  • Let users choose which project to inspect

The project list endpoint returns one item per project. Treat each project _id as the value you pass into later project-level endpoints. For user-facing labels, combine readable fields such as name, project_number, and client_name instead of exposing only the UUID.

  • Important: Use project _id as project_id - do not use project name as the identifier for later endpoints

Common project fields:

  • _id
  • name
  • project_number
  • client_name
  • status
  • date_created
  • date_updated
  • nda_strict

Expand to see all available response fields

In alphabetical order:

  • _id
  • accessors
  • analyte_settings_id
  • automated_notes_id
  • branding_id
  • client_name
  • comments
  • consultant_project_number
  • corporation_id
  • county_code
  • date_created
  • date_updated
  • district
  • dropdowns_id
  • facility_id
  • field_workflow_id
  • from_upload
  • library_id
  • location
  • location_id
  • mapping_rules
  • mapping_rules_id
  • n_value_id
  • name
  • nda_strict
  • project_manager
  • project_number
  • project_owner_logo
  • project_owner_name
  • project_type
  • region
  • sampling_configurations
  • sitemap_configuration
  • spell_check_id
  • status
  • stratigraphic_unit_definitions
  • template_configuration
  • unit_id
  • visual_description_config
  • visual_description_config_id
  • watermark_mapping_id

Example response:

[
{
"_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Downtown Bridge Project",
"project_number": "2024-001",
"client_name": "City Engineering",
"status": ["Active"],
"date_created": "2024-01-15T14:30:00Z",
"date_updated": "2024-01-15T14:30:00Z",
"corporation_id": "550e8400-e29b-41d4-a716-446655440000",
"nda_strict": true
}
]

BoreDM data endpoints

Use the tabs below to explore each data type:

What the GeoJSON endpoint does

Endpoint: GET /api/v4/project/{project_id}/geojson

This endpoint returns a GeoJSON feature collection where each feature represents one borehole. The critical field is feature.properties.id, which serves as the log_id for joining lithology, sample, and specimen records.

Important: Always use feature.properties.id as the log ID, never the boring name string.

Common GeoJSON fields:

  • feature.properties.id - Unique log ID (use this for joins)
  • feature.properties.name - Boring name
  • feature.properties.boringType - Type of boring
  • feature.properties.status - Current status
  • feature.geometry.coordinates - [longitude, latitude] array

Expand to see all available response fields

In alphabetical order:

  • features
  • features.geometry
  • features.geometry.coordinates
  • features.geometry.type
  • features.properties
  • features.properties.boringType
  • features.properties.depth
  • features.properties.id
  • features.properties.name
  • features.properties.status
  • features.type
  • type

Example response:

{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-77.0369, 38.9072]
},
"properties": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "B-1",
"boringType": "Boring",
"depth": 50.0,
"status": "Complete"
}
}
]
}

Implementation examples

The following implementation examples demonstrate complete, ready-to-use code for common BoreDM integration patterns in VIKTOR apps. Each example shows the full function or class definition you can copy into your app.py.

Create a project selector

Create an OptionField that lets users select a BoreDM project by combining the project name, number, and client name into a readable label.

import os
import requests
import viktor as vkt

def project_options(params, **kwargs) -> list[vkt.OptionListElement]:
response = requests.get(
"https://boredm.com/api/v4/project/",
headers={
"Authorization": f"Secret {os.environ['BOREDM_API_KEY']}",
"Accept": "application/json",
},
timeout=30,
)
response.raise_for_status()
projects = response.json()

options = []
for project in projects:
project_id = project.get("_id")
if not project_id:
continue

name = project.get("name") or "Unnamed project"
number = project.get("project_number") or "No number"
client = project.get("client_name") or "No client"
label = f"{name} | {number} | {client}"

options.append(vkt.OptionListElement(value=project_id, label=label[:90]))

return options

class Parametrization(vkt.Parametrization):
project_id = vkt.OptionField("Project", options=project_options)

Show projects in a TableView

Display all available projects in a table with their key information (ID, name, project number, client, and status).

@vkt.TableView("Projects", duration_guess=2)
def projects_table(self, params, **kwargs):
response = requests.get(
"https://boredm.com/api/v4/project/",
headers={
"Authorization": f"Secret {os.environ['BOREDM_API_KEY']}",
"Accept": "application/json",
},
timeout=30,
)
response.raise_for_status()
projects = response.json()

rows = []
for project in projects:
rows.append([
project.get("_id"),
project.get("name"),
project.get("project_number"),
project.get("client_name"),
", ".join(project.get("status") or []),
])

return vkt.TableResult(
rows,
column_headers=["Project ID", "Name", "Number", "Client", "Status"],
)

Connecting BoreDM data

The implementation examples above show how to retrieve data from individual endpoints. To build more advanced features, like associating SPT N-values with soil layers or linking lab results to field samples, you'll need to join data across multiple endpoints.

BoreDM data follows a hierarchical structure where projects contain logs (boreholes), and each log contains data tables like lithology, samples, and specimens. To work with this data effectively, follow the ID relationships rather than relying on string names.

Basic relationship chain

  1. Select a project from /api/v4/project/ and use its _id as project_id
  2. Get logs from /api/v4/project/{project_id}/geojson and use feature.properties.id as the log ID
  3. Join lithology, samples, and specimens to logs using their log_id field
  4. Join specimens to samples using specimen.sample_id = sample._id
  5. Join samples to lithology by matching both log_id and depth interval
warning

Do not use boring names as join keys. Always use BoreDM IDs (_id or id fields) to ensure reliable data relationships.


Conclusion

By following this guide, you've learned how to authenticate with the BoreDM API, retrieve project and log data, work with lithology, samples, and specimens, and visualize geotechnical data in VIKTOR apps. You now have the templates and patterns you need to integrate BoreDM with your applications and automate your geotechnical data workflows.