API reference

A JSON REST API for finite-element structural analysis. Base URL https://api.physicsbase.dev. Every request and response is JSON; every problem uses the same object across all endpoints.

Introduction

Send a Problem object, get a Result back. The endpoint (or the analysis field) selects static, modal, buckling, or transient. There is no state between calls — each solve is independent, which makes the API safe for agents to fan out over.

bash · a complete requestcopy
curl -X POST https://api.physicsbase.dev/solve \
  -H "content-type: application/json" \
  -d '{
    "nodes": [[0,0],[2,0]],
    "materials": {"steel": {"E": 200e9, "nu": 0.3}},
    "elements": [{"type":"truss2d","nodes":[0,1],"material":"steel","section":{"A":0.01}}],
    "supports": [{"node":0,"dofs":["ux","uy"]},{"node":1,"dofs":["uy"]}],
    "loads": [{"node":1,"fx":50000}]
  }'

Authentication

None required. physicsbase is free during the research preview — no API key, no sign-up, no bearer token. Point your agent at the endpoint and POST. Every solve is stateless, so there is nothing to provision.

Errors & status codes

Errors return a JSON body with a detail string written to be actioned directly (a bad support, a singular model, an unknown element).

CodeMeaning
200OK — results in the body.
422Invalid problem — detail says what to fix (e.g. "no supports; stiffness is singular").
429Rate or quota limit reached.
500Unexpected solve failure — safe to retry.
json · 422 bodycopy
{ "detail": "support dof 'rz' invalid (allowed: ['ux', 'uy'])" }

Rate limits

Generous limits during the research preview — free, no key required. Responses include X-RateLimit-Remaining and X-RateLimit-Reset headers. On 429, back off and retry after the reset.

The Problem object

The single input shared by every endpoint.

FieldTypeDescription
nodes requirednumber[][]Coordinates, [x,y] (2D) or [x,y,z] (3D).
materials requiredobjectName → {E, nu, rho?, alpha?}.
elements requiredobject[]{type, nodes, material, section, id?}. See element reference.
supportsobject[]{node, dofs[], values?}. values = prescribed displacement.
loadsobject[]{node, fx?, fy?, fz?, mx?, my?, mz?}.
element_loadsobject[]{element, w[]} distributed load on a beam/frame.
springsobject[]{node, dof, k} grounded elastic support.
thermalobject[]{element, dT} temperature rise (needs material alpha).
body_forcesobject[]{element, b[]} force per unit volume.
tractionsobject[]{nodes[], traction[], thickness} edge/surface pressure.
gravitynumber[]Acceleration vector for self-weight, e.g. [0,-9.81].
analysisstringstatic (default), modal, buckling, transient.
num_modesintModes returned for modal/buckling (default 6).
dt, n_stepsnumber, intTime step and step count for transient.
dampingnumber[]Rayleigh [alpha, beta] for transient.
titlestringOptional label echoed in the summary.

The Result object

Static and transient share the displacement/reaction shape; modal and buckling return spectra. Every response carries a summary.

json · static resultcopy
{
  "displacements": [ { "ux": 0.0, "uy": 0.0 }, … ],
  "reactions":     [ { "fx": -50000.0, "fy": 0.0 }, … ],
  "elements": [ { "type": "truss2d", "axial_force": 50000.0,
                "axial_stress": 5.0e6 }, … ],
  "summary": { "n_dof": 4, "max_abs_displacement": 5e-5,
                "analysis": "static", "solve_ms": 1.2 } }

POST /solve

Runs the analysis named in the problem's analysis field — static by default. The catch-all endpoint; the others are conveniences.

Returns

A Result: displacements, reactions, per-element forces/stresses, and summary. Element results depend on type — trusses give axial_force, beams give moment_i/j, continuum/solids give a stress vector and von_mises.

POST /modal

Natural frequencies and mode shapes, solving (K − ω²M) φ = 0. Materials must include rho; applied loads are ignored.

json · responsecopy
{
  "frequencies_hz": [ 9.1, 57.0, 159.6, … ],
  "angular_frequencies": [ … ],
  "mode_shapes": [ [ {"ux":0,"uy":0,"rz":0}, … ], … ],
  "summary": { "num_modes": 6, "analysis": "modal" } }

POST /buckling

Linear buckling. The applied loads define the reference pattern; load_factors multiply it to reach instability and critical_loads give the magnitudes.

json · responsecopy
{
  "load_factors": [ 1842.1, … ],
  "critical_loads": [ 1842100.0, … ],
  "mode_shapes": [ … ],
  "summary": { "reference_load": 1000.0, "analysis": "buckling" } }

POST /transient

Newmark step response. Loads are held constant from t=0 with zero initial conditions. Set dt, n_steps, optional damping and monitor = [node, dof].

json · responsecopy
{
  "times": [ … ], "peak_displacement": 0.0521, "peak_time": 0.018,
  "frames": [ {"t":…, "max_abs_displacement":…}, … ],
  "monitor": { "node": 1, "dof": "uy", "history": [ … ] },
  "summary": { "dt": 2e-4, "n_steps": 150, "analysis": "transient" } }

GET /capabilities

Machine-readable description of everything the engine supports — element types, DOF names, load components, analyses, and extras. Agents should call this first to build a valid problem.

bashcopy
curl -s https://api.physicsbase.dev/capabilities

GET /health

Liveness check. Returns {"status":"ok","version":"…"}. No auth required.

Prefer native tools? The same capabilities are exposed over MCP (fem_solve, fem_modal, fem_buckling, fem_transient) and a Python SDK — see the docs.