Python SDK
The boreholeai Python package provides a high-level client for the BoreholeAI API. Upload borehole log PDFs or images, get structured ground profiles, test data, and annotated PDFs — all from Python.
Installation
Install the package from PyPI using pip. Requires Python 3.9 or later.
bash
pip install boreholeaiThe SDK has minimal dependencies: httpx for HTTP requests. No heavy ML frameworks are installed — all processing happens server-side.
Authentication
All API requests require an API key. Get yours from the API Keys settings page. Your API key starts with bhai_.
Python
from boreholeai import BoreholeAI
# Pass the API key directly
client = BoreholeAI(api_key="bhai_your_api_key_here")Security: Never commit your API key to version control or share it publicly. Store it in an environment variable or secrets manager. You can revoke a compromised key at any time from the dashboard and create a new one.
Using Environment Variables
Instead of passing the API key directly, you can store it in an environment variable and load it automatically using python-dotenv. This keeps your key out of source code.
1. Install python-dotenv
bash
pip install python-dotenv2. Create a .env file
Add a .env file to your project root with your API key. Make sure to add .env to your .gitignore so the key is never committed.
.env
BOREHOLEAI_API_KEY=bhai_your_api_key_here3. Load the key in your script
Use load_dotenv() to read the .env file, then retrieve the key with os.getenv().
Python
import os
from dotenv import load_dotenv
from boreholeai import BoreholeAI
load_dotenv()
api_key = os.getenv("BOREHOLEAI_API_KEY")
client = BoreholeAI(api_key=api_key)4. Pass an existing shell variable explicitly
If BOREHOLEAI_API_KEY is already set in your shell or deployment environment, read it with os.environ and pass it to the client. The SDK does not load the variable automatically.
Python
import os
from boreholeai import BoreholeAI
client = BoreholeAI(api_key=os.environ["BOREHOLEAI_API_KEY"])Basic Usage
Processing a Single File
Pass the path to a borehole log PDF or image. The SDK uploads the file, waits for processing to complete, downloads the results, and returns a JobResult object.
Python
from boreholeai import BoreholeAI
client = BoreholeAI(api_key="bhai_your_api_key_here")
result = client.process_documents("BH01.pdf", output_dir="./results")
print(f"Job ID: {result.job_id}")
print(f"Status: {result.status}")
print(f"Pages processed: {result.num_pages}")
print(f"Credits used: {result.credits_used}")
for f in result.files:
print(f" {f.filename} → {f.path}")The output_dir parameter specifies where result files are saved. If not provided, the SDK uses ./results. A successful single-file run saves the two Excel files, AGS file, and Borehole_data.json directly in that directory. The annotated PDF is saved under annotated_pdf/.
Processing a Folder
Pass a directory path to process all supported files in the folder together. When at least two files complete successfully, their results are merged into consolidated output files with an _merged suffix.
Python
result = client.process_documents("./borehole_logs/", output_dir="./results")
print(f"Total pages: {result.num_pages}")
print(f"Total credits: {result.credits_used}")
# Output files:
# results/Borehole_ground_profile_merged.xlsx
# results/Borehole_test_data_merged.xlsx
# results/Borehole_ags4_merged.ags
# results/Borehole_data_merged.json
# results/annotated_pdf/BH01_annotated.pdf
# results/annotated_pdf/BH02_annotated.pdf
# results/annotated_pdf/BH03_annotated.pdfThe SDK automatically discovers all supported file types in the directory (PDF, PNG, JPEG, TIFF, WebP). Subdirectories are not scanned — only files directly in the specified directory are processed.
Error Handling
The SDK raises local validation errors before processing starts. For example, a missing path raises FileNotFoundError, while an unsupported file or a folder with no supported files raises ValueError. Once the batch workflow starts, per-file submission, processing, polling, and download failures are normally returned in the JobResult. Whole-call setup, manifest, merge, or local file-system errors can still raise an exception and should be handled where appropriate for your application.
Python
from boreholeai import BoreholeAI
client = BoreholeAI(api_key="bhai_xxx")
try:
result = client.process_documents("./borehole_logs/", output_dir="./results")
except (FileNotFoundError, ValueError) as exc:
print(f"Check the local input: {exc}")
else:
print(f"Batch status: {result.status}")
for filename, message in result.failures.items():
print(f"Failed — {filename}: {message}")
for filename, message in result.warnings.items():
print(f"Completed with warnings — {filename}: {message}")| Field | How to use it |
|---|---|
| status | completed, partial, or failed for the overall batch. |
| failures | Maps each failed input filename to the error reported for that file. |
| warnings | Maps successfully processed input filenames to page-level extraction warnings. |
| files | Lists the final output files successfully copied or merged. |
Response Types
The process_documents() method returns a JobResult dataclass containing the job status and a list of downloaded files.
Python
@dataclass
class JobResult:
job_id: str # Primary job identifier
status: str # "completed" | "partial" | "failed"
num_pages: int # Total pages across all jobs
credits_used: int # Credits consumed
files: list[FileResult] # Downloaded and merged outputs
job_ids: list[str] # All server-side job IDs
successes: list[str] # Successfully processed input filenames
failures: dict[str, str] # Failed input filename → error
warnings: dict[str, str] # Completed input filename → page warning
@dataclass
class FileResult:
filename: str # e.g. "Borehole_ground_profile.xlsx"
path: Path # Local path where file was savedThe files list contains one entry per output file. For a single-file job, you will typically receive five files: two Excel workbooks, one AGS4 file, one JSON file, and one annotated PDF. When at least two folder inputs complete successfully, the Excel, AGS, and JSON filenames include _merged, and the annotated PDFs are stored in the annotated_pdf/ subdirectory.
Supported File Types
The following file types can be uploaded for processing:
When processing a folder, the SDK automatically discovers all files with these extensions. Other file types are ignored. Maximum file size is 90 MB per file.
Resume & Cleanup
The SDK stores resume state in .boreholeai_manifest.json and .boreholeai_workdir/ inside your output directory. If a run is interrupted, repeat the same call with the same input and output paths. Completed files are skipped and unfinished work resumes.
After a fully successful run in an interactive terminal, the default behavior asks whether to remove this resume state. Answering y removes it; pressing Enter, answering no, or running non-interactively keeps it. Partial and failed runs always keep their resume state.
Python
# Keep resume state and never prompt
result = client.process_documents(
"./borehole_logs/",
output_dir="./results",
finalise_and_cleanup=False,
)
# Or remove resume state after a fully successful run
result = client.process_documents(
"./borehole_logs/",
output_dir="./results",
finalise_and_cleanup=True,
)Complete Example
A complete end-to-end example that processes a folder of borehole logs and prints the results.
Python
from boreholeai import BoreholeAI
client = BoreholeAI(api_key="bhai_your_api_key_here")
try:
result = client.process_documents(
"./site_investigation/borehole_logs/",
output_dir="./extracted_data",
)
print(f"Batch status: {result.status}")
print(f" Pages processed: {result.num_pages}")
print(f" Credits used: {result.credits_used}")
print(f" Output files:")
for f in result.files:
print(f" {f.filename}")
print(f" → {f.path}")
for filename, message in result.failures.items():
print(f" Failed — {filename}: {message}")
for filename, message in result.warnings.items():
print(f" Warning — {filename}: {message}")
except (FileNotFoundError, ValueError) as exc:
print(f"Check the local input: {exc}")