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.
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).
| Code | Meaning |
|---|---|
200 | OK — results in the body. |
422 | Invalid problem — detail says what to fix (e.g. "no supports; stiffness is singular"). |
429 | Rate or quota limit reached. |
500 | Unexpected solve failure — safe to retry. |
{ "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.
| Field | Type | Description |
|---|---|---|
nodes required | number[][] | Coordinates, [x,y] (2D) or [x,y,z] (3D). |
materials required | object | Name → {E, nu, rho?, alpha?}. |
elements required | object[] | {type, nodes, material, section, id?}. See element reference. |
supports | object[] | {node, dofs[], values?}. values = prescribed displacement. |
loads | object[] | {node, fx?, fy?, fz?, mx?, my?, mz?}. |
element_loads | object[] | {element, w[]} distributed load on a beam/frame. |
springs | object[] | {node, dof, k} grounded elastic support. |
thermal | object[] | {element, dT} temperature rise (needs material alpha). |
body_forces | object[] | {element, b[]} force per unit volume. |
tractions | object[] | {nodes[], traction[], thickness} edge/surface pressure. |
gravity | number[] | Acceleration vector for self-weight, e.g. [0,-9.81]. |
analysis | string | static (default), modal, buckling, transient. |
num_modes | int | Modes returned for modal/buckling (default 6). |
dt, n_steps | number, int | Time step and step count for transient. |
damping | number[] | Rayleigh [alpha, beta] for transient. |
title | string | Optional 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.
{
"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.
{
"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.
{
"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].
{
"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.
curl -s https://api.physicsbase.dev/capabilities
GET /health
Liveness check. Returns {"status":"ok","version":"…"}. No auth
required.
fem_solve, fem_modal,
fem_buckling, fem_transient) and a Python SDK — see
the docs.