Wellbore Genius
SimulationsSDK & REST API

SDK & REST API

Drop Wellbore Genius solvers into your notebook or pipeline. JSON over HTTPS, bearer-token auth, team-scoped. Mint a key under Settings → SDK API keys.

Authentication

Every request must include an Authorization header with a bearer token minted from Settings. Tokens look like dh_live_… and are shown only once at mint time. Revoke under Settings; last_used_at bumps on every successful call.

GET /api/public/sdk/v1/solver-spec

Returns the full solver-spec scoreboard — every coupling kernel's "Today" vs "Roadmap" stance. Stable JSON shape, mirrors the in-app /solver-spec page.

curl https://wellboregenius.com/api/public/sdk/v1/solver-spec \
  -H "Authorization: Bearer dh_live_..."
POST /api/public/sdk/v1/non-planar-3d/run

Drives the non-planar 3D fracture pipeline (DDM + tip kinking + optional out-of-plane tilt and stress-driven curvature) on a synthetic rectangular mesh. Returns per-step history + final mesh summary.

curl -X POST https://wellboregenius.com/api/public/sdk/v1/non-planar-3d/run \
  -H "Authorization: Bearer dh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "halfLengthFt": 300,
    "halfHeightFt": 150,
    "elementSizeFt": 30,
    "ePrimePsi": 4500000,
    "defaultNetPressurePsi": 350,
    "defaultSigmaHPsi": 4200,
    "advanceFt": 25,
    "maxKinkDeg": 10,
    "steps": 8
  }'
Python client (thin wrapper)

A pip install downhole wrapper will ship separately. In the meantime, a dependency-free typed client (stdlib only) is bundled at /sdk/python/downhole_sdk.py. It includes typed dataclasses + Bearer auth for parent_child_analyze(). Or call the API directly:

# pip install requests
import requests

API_KEY = "dh_live_..."
BASE = "https://wellboregenius.com/api/public/sdk/v1"
H = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

def solver_spec():
    r = requests.get(f"{BASE}/solver-spec", headers=H)
    r.raise_for_status()
    return r.json()

def non_planar_3d_run(**kwargs):
    r = requests.post(f"{BASE}/non-planar-3d/run", headers=H, json=kwargs)
    r.raise_for_status()
    return r.json()

def parent_child_analyze(parents, child, reservoir, **kwargs):
    payload = {"parents": parents, "child": child, "reservoir": reservoir, **kwargs}
    r = requests.post(f"{BASE}/parent-child/analyze", headers=H, json=payload)
    r.raise_for_status()
    return r.json()

# Simulations CRUD ----------------------------------------------------------
def list_simulations(workspace_id=None, limit=200):
    params = {"limit": limit}
    if workspace_id:
        params["workspaceId"] = workspace_id
    r = requests.get(f"{BASE}/simulations", headers=H, params=params)
    r.raise_for_status()
    return r.json()["simulations"]

def create_simulation(workspace_id, name, **kwargs):
    payload = {"workspaceId": workspace_id, "name": name, **kwargs}
    r = requests.post(f"{BASE}/simulations", headers=H, json=payload)
    r.raise_for_status()
    return r.json()

def get_simulation(sim_id):
    r = requests.get(f"{BASE}/simulations/{sim_id}", headers=H)
    r.raise_for_status()
    return r.json()

def update_simulation(sim_id, **patch):
    r = requests.patch(f"{BASE}/simulations/{sim_id}", headers=H, json=patch)
    r.raise_for_status()
    return r.json()

def delete_simulation(sim_id):
    r = requests.delete(f"{BASE}/simulations/{sim_id}", headers=H)
    r.raise_for_status()
    return r.json()

if __name__ == "__main__":
    print(solver_spec()["count"], "scoreboard rows")

    np3d = non_planar_3d_run(
        halfLengthFt=300, halfHeightFt=150, elementSizeFt=30,
        ePrimePsi=4_500_000, defaultNetPressurePsi=350,
        defaultSigmaHPsi=4200, advanceFt=25, maxKinkDeg=10, steps=8,
    )
    print("np3D steps:", len(np3d["history"]), "final mesh:", np3d["finalMesh"])

    pc = parent_child_analyze(
        parents=[
            {"id":"P1","heel":{"x":0,"y":660},"toe":{"x":10000,"y":660},"drawdownPsi":1000},
            {"id":"P2","heel":{"x":0,"y":-660},"toe":{"x":10000,"y":-660},"drawdownPsi":1000},
        ],
        child={"id":"C1","heel":{"x":0,"y":0},"toe":{"x":10000,"y":0},"stageCount":50},
        reservoir={"biotAlpha":0.85,"poissonRatio":0.22},
    )
    print("parent-child worst stage:", pc["summary"]["worstStageId"])

    sim = create_simulation("default", "bakken_baseline", tags=["history-match"])
    update_simulation(sim["simulation"]["id"], status="completed",
                      runtimeSeconds=1843, results={"peakBhpPsi": 9120})
    print("simulations on team:", len(list_simulations()))
POST /api/public/sdk/v1/parent-child/analyze

Runs the analytical parent–child interference engine. Returns per-stage Δp, Δσ_h, asymmetry %, nearest parent, and bashing-risk chip — plus the rolled-up summary.

curl -X POST https://wellboregenius.com/api/public/sdk/v1/parent-child/analyze \
  -H "Authorization: Bearer dh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "parents": [
      {"id":"P1","heel":{"x":0,"y":660},"toe":{"x":10000,"y":660},"drawdownPsi":1000},
      {"id":"P2","heel":{"x":0,"y":-660},"toe":{"x":10000,"y":-660},"drawdownPsi":1000}
    ],
    "child": {"id":"C1","heel":{"x":0,"y":0},"toe":{"x":10000,"y":0},"stageCount":50},
    "reservoir": {"biotAlpha":0.85,"poissonRatio":0.22}
  }'

Response schema (200 OK)

stages[] — one entry per child stage, ordered heel→toe:

  • stageIndex (number) — 0-based index.
  • stageLabel (string) — 1-based UI label, e.g. "Stage 12".
  • midpoint ({x, y}) — stage centroid in plan view [ft].
  • depletionPsi (number) — depletion-induced Δp at the stage [psi].
  • dSigmaHPsi (number) — Eaton Δσ_h from depletion [psi].
  • asymmetryPct (number, −100..+100) — signed half-length skew toward the more-depleted side.
  • nearestParentId (string | null) — id of closest parent, or null if none.
  • nearestParentFt (number) — perpendicular distance to nearest parent [ft].
  • bashingRisk ("low" | "watch" | "high") — frac-hit severity chip.

summary — roll-up across all stages:

  • highCount, watchCount, lowCount (number) — stages in each risk bucket.
  • worstStageId (string | null) — stageLabel of the highest-Δp stage.
  • worstDepletionPsi (number) — max Δp across stages [psi].
  • meanDepletionPsi (number) — mean Δp across stages [psi].
  • meanDSigmaHPsi (number) — mean Δσ_h across stages [psi].

Example response

{
  "stages": [
    {
      "stageIndex": 0,
      "stageLabel": "Stage 1",
      "midpoint": { "x": 100, "y": 0 },
      "depletionPsi": 312.4,
      "dSigmaHPsi": 187.6,
      "asymmetryPct": 4.2,
      "nearestParentId": "P1",
      "nearestParentFt": 660,
      "bashingRisk": "watch"
    },
    {
      "stageIndex": 1,
      "stageLabel": "Stage 2",
      "midpoint": { "x": 300, "y": 0 },
      "depletionPsi": 540.1,
      "dSigmaHPsi": 324.0,
      "asymmetryPct": -8.7,
      "nearestParentId": "P2",
      "nearestParentFt": 660,
      "bashingRisk": "high"
    }
  ],
  "summary": {
    "highCount": 1,
    "watchCount": 1,
    "lowCount": 0,
    "worstStageId": "Stage 2",
    "worstDepletionPsi": 540.1,
    "meanDepletionPsi": 426.25,
    "meanDSigmaHPsi": 255.8
  }
}
Simulations CRUD

Team-scoped simulation rows. Same shape used by the in-app Cloud simulations page. Status must be one of not_yet_submitted, queued, running, completed, failed, cancelled.

# List
curl https://wellboregenius.com/api/public/sdk/v1/simulations \
  -H "Authorization: Bearer dh_live_..."

# Create
curl -X POST https://wellboregenius.com/api/public/sdk/v1/simulations \
  -H "Authorization: Bearer dh_live_..." \
  -H "Content-Type: application/json" \
  -d '{"workspaceId":"default","name":"bakken_baseline","tags":["history-match"]}'

# Retrieve (includes results JSON)
curl https://wellboregenius.com/api/public/sdk/v1/simulations/<id> \
  -H "Authorization: Bearer dh_live_..."

# Update status / attach results
curl -X PATCH https://wellboregenius.com/api/public/sdk/v1/simulations/<id> \
  -H "Authorization: Bearer dh_live_..." \
  -H "Content-Type: application/json" \
  -d '{"status":"completed","runtimeSeconds":1843,"results":{"peakBhpPsi":9120}}'

# Delete
curl -X DELETE https://wellboregenius.com/api/public/sdk/v1/simulations/<id> \
  -H "Authorization: Bearer dh_live_..."
Roadmap
  • POST /sensitivity/run — OFAT factor sweeps
  • Published pip install downhole with typed dataclasses