API: laterally loaded pile

POST /v1/lateral — request and response fields for the COM624P p-y analysis, with runnable curl, JavaScript, and Python examples.


Solves a laterally loaded single pile by the p-y method — a beam supported by nonlinear soil springs, solved with the COM624P finite-difference formulation (Wang & Reese, FHWA-SA-91-048), the same engine behind LPILE and RSPile. It returns head response, maxima, and the full deflection / moment / shear profile. The method and every input are explained in Laterally loaded piles (p-y); the same analysis runs interactively at the lateral tool.

Endpoint

POST
https://api.pilecalc.com/v1/lateral
GET
/v1/lateral?key=…&req=…&fields=…(for header-less callers)

The request has three required parts: the pile (uniform, or sectioned with depth-varying diameter/ei), the soil profile (a stack of layers, each tagged with a p-y model — Matlock soft clay, Reese stiff clay, Reese or API sand, weak rock, elastic, or user-defined curves), and the head boundary condition (five variants covering free, fixed, and rotationally restrained heads). Optional fields add an axial load, cyclic loading, distributed loads, ground slope, a p-multiplier, and free-field soil movement. Two more options change what comes back: sweep solves a series of proportionally scaled head loads (a pushover curve) in one call, and section + material replace the constant pile EI with the section's fiber-integrated moment–curvature stiffness (cracked-section nonlinear EI) — see Load sweep and Cracked section.

Authentication, rate limits, and the error envelope are shared by every endpoint — see the API overview. Requests are unit-agnostic: any self-consistent unit system works, and results come back in the same units. The examples below use SI (m, kN, kPa, kN/m³).

Request fields

This table is generated from the same schema that validates the request, so it cannot drift. Where a field appears once per variant row, it belongs to that variant only.

FieldTypeRequiredConstraints
unitSystem"si" | "us"yes
pileobjectyes
pile.kind = "uniform"variantno
pile.lengthnumberyes> 0
pile.diameternumberyes> 0
pile.einumberyes> 0
pile.groundSurfaceDepthnumberno≥ 0
pile.kind = "sectioned"variantyes
pile.sectionsobject | object[]yesmin 1 item
pile.groundSurfaceDepthnumberno≥ 0
soilobjectyes
soil.layers[]object[]yesmin 1 item
soil.layers[].model = "soft-clay"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].cnumberyes> 0
soil.layers[].cBottomnumberno> 0
soil.layers[].e50numberyes> 0
soil.layers[].e50Bottomnumberno> 0
soil.layers[].jnumberno> 0
soil.layers[].model = "stiff-clay-above-water"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].cnumberyes> 0
soil.layers[].cBottomnumberno> 0
soil.layers[].e50numberyes> 0
soil.layers[].e50Bottomnumberno> 0
soil.layers[].jnumberno> 0
soil.layers[].knumberno> 0
soil.layers[].kBottomnumberno> 0
soil.layers[].model = "stiff-clay-below-water"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].cnumberyes> 0
soil.layers[].cBottomnumberno> 0
soil.layers[].e50numberyes> 0
soil.layers[].e50Bottomnumberno> 0
soil.layers[].knumberyes> 0
soil.layers[].kBottomnumberno> 0
soil.layers[].model = "sand-reese"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].phinumberyes0 – 60
soil.layers[].phiBottomnumberno0 – 60
soil.layers[].knumberyes> 0
soil.layers[].kBottomnumberno> 0
soil.layers[].model = "sand-api"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].phinumberyes0 – 60
soil.layers[].phiBottomnumberno0 – 60
soil.layers[].knumberyes> 0
soil.layers[].kBottomnumberno> 0
soil.layers[].model = "weak-rock"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].qunumberyes> 0
soil.layers[].quBottomnumberno> 0
soil.layers[].eirnumberyes> 0
soil.layers[].eirBottomnumberno> 0
soil.layers[].rqdnumberyes0 – 100
soil.layers[].rqdBottomnumberno0 – 100
soil.layers[].krmnumberno> 0
soil.layers[].model = "elastic"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].esTopnumberyes≥ 0
soil.layers[].esBottomnumberno≥ 0
soil.layers[].model = "user"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].esnumberno≥ 0
soil.layers[].curves[]object[]no
soil.layers[].curves[].depthnumberyes≥ 0
soil.layers[].curves[].points[]object[]yesmin 2 items
soil.layers[].curves[].points[].ynumberyes≥ 0
soil.layers[].curves[].points[].pnumberyes≥ 0
soil.layers[].model = "liquefied-sand"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].units"SI" | "US"yes
soil.layers[].model = "silt-cphi"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].cnumberyes> 0
soil.layers[].cBottomnumberno> 0
soil.layers[].phinumberyes0 – 60
soil.layers[].phiBottomnumberno0 – 60
soil.layers[].knumberyes> 0
soil.layers[].kBottomnumberno> 0
soil.layers[].jnumberno> 0
soil.layers[].model = "piedmont-residual"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].esinumberyes> 0
soil.layers[].esiBottomnumberno> 0
soil.layers[].lambdanumberno> 0
soil.layers[].model = "iso-clay"variantyes
soil.layers[].topnumberyes≥ 0
soil.layers[].bottomnumberyes> 0
soil.layers[].gammanumberyes> 0
soil.layers[].gammaBottomnumberno> 0
soil.layers[].sunumberyes> 0
soil.layers[].suBottomnumberno> 0
soil.layers[].alphanumberno0 – 1
soil.layers[].gap"open" | "closed"no
soil.layers[].clayType"soft" | "stiff"no
soil.cyclesnumbernointeger, > 0
headobjectyes
head.kind = "shear-moment"variantyes
head.shearnumberyes
head.momentnumberyes
head.kind = "shear-slope"variantyes
head.shearnumberyes
head.slopenumberyes
head.kind = "shear-rotational"variantyes
head.shearnumberyes
head.rotationalStiffnessnumberyes≥ 0
head.kind = "deflection-moment"variantyes
head.deflectionnumberyes
head.momentnumberyes
head.kind = "deflection-slope"variantyes
head.deflectionnumberyes
head.slopenumberyes
tipobjectno
tip.shearnumberno
tip.momentnumberno
axialLoadnumberno
loadType"static" | "cyclic"no
incrementsnumbernointeger, 10 – 800
layering"direct" | "georgiadis"no
groundSlopeDegnumberno0 – 45
pMultipliernumberno0 – 1
pMultiplierProfile[]object[]nomin 2 items
pMultiplierProfile[].depthnumberyes≥ 0
pMultiplierProfile[].factornumberyes0 – 1
tipShearCurve[]object[]nomin 2 items
tipShearCurve[].deflectionnumberyes≥ 0
tipShearCurve[].shearnumberyes≥ 0
distributedLoadobjectno
distributedLoad.intensitynumberyes
distributedLoad.topnumberno≥ 0
distributedLoad.bottomnumberno≥ 0
soilMovementobjectno
soilMovement.magnitudenumberyes
soilMovement.slidingDepthnumberyes> 0
sweepobjectno
sweep.stepsnumberyesinteger, 2 – 50
sweep.maxShearnumberno
sweep.maxMomentnumberno
sectionobjectno
section.kind = "solid-circular"variantyes
section.diameternumberyes> 0
section.kind = "pipe"variantyes
section.outerDiameternumberyes> 0
section.wallThicknessnumberyes> 0
section.kind = "rectangular"variantyes
section.widthnumberyes> 0
section.heightnumberyes> 0
section.kind = "round-concrete"variantyes
section.diameternumberyes> 0
section.cageobjectno
section.cage.countnumberyesinteger, 1 – 200
section.cage.areanumberyes> 0
section.cage.barDiameternumberyes> 0
section.cage.barCircleRadiusnumberyes> 0
section.cage.yieldStressnumberyes> 0
section.cage.elasticModulusnumberyes> 0
section.cage.effectivePrestrainnumberno≥ 0
section.cage.hardeningRationumberno0 – 1
section.cage.tensionRuptureStrainnumberno> 0
section.rebarConcreteDisplacement"subtract" | "overlap"no
section.casingobjectno
section.casing.outerDiameternumberyes> 0
section.casing.wallThicknessnumberyes> 0
section.casing.yieldStressnumberyes> 0
section.casing.elasticModulusnumberyes> 0
section.casing.hardeningRationumberno0 – 1
section.casing.tensionRuptureStrainnumberno> 0
section.coreobjectno
section.core.outerDiameternumberyes> 0
section.core.wallThicknessnumberyes> 0
section.core.yieldStressnumberyes> 0
section.core.elasticModulusnumberyes> 0
section.core.hardeningRationumberno0 – 1
section.core.tensionRuptureStrainnumberno> 0
section.kind = "rectangular-concrete"variantyes
section.widthnumberyes> 0
section.heightnumberyes> 0
section.reinforcementobjectno
section.reinforcement.layout"perimeter"yes
section.reinforcement.barsPerFacenumberyesinteger, 2 – 100
section.reinforcement.barsPerSidenumberyesinteger, 0 – 99
section.reinforcement.areanumberyes> 0
section.reinforcement.barDiameternumberyes> 0
section.reinforcement.clearCovernumberyes> 0
section.reinforcement.yieldStressnumberyes> 0
section.reinforcement.elasticModulusnumberyes> 0
section.reinforcement.effectivePrestrainnumberno≥ 0
section.reinforcement.hardeningRationumberno0 – 1
section.reinforcement.tensionRuptureStrainnumberno> 0
section.rebarConcreteDisplacement"subtract" | "overlap"no
section.confinedCoreobjectno
section.confinedCore.coverDepthnumberyes> 0
section.confinedCore.materialobjectyes
section.confinedCore.material.kind"concrete"yes
section.confinedCore.material.compressiveStrengthnumberyes> 0
section.confinedCore.material.elasticModulusnumberno> 0
section.confinedCore.material.peakStrainnumberno> 0
section.confinedCore.material.ultimateStrainnumberno> 0
section.confinedCore.material.descendingStrainnumberno> 0
section.confinedCore.material.tensileStrengthnumberno≥ 0
section.confinedCore.material.model"todeschini" | "hognestad" | "concrete01"no
section.confinedCore.material.residualStrengthnumberno≥ 0
materialobjectno
material.kind = "concrete"variantyes
material.compressiveStrengthnumberyes> 0
material.elasticModulusnumberno> 0
material.peakStrainnumberno> 0
material.ultimateStrainnumberno> 0
material.descendingStrainnumberno> 0
material.tensileStrengthnumberno≥ 0
material.model"todeschini" | "hognestad" | "concrete01"no
material.residualStrengthnumberno≥ 0
material.kind = "steel"variantno
material.elasticModulusnumberyes> 0
material.yieldStressnumberyes> 0
material.hardeningRationumberno0 – 1
material.ultimateStrainnumberno> 0
eiCurve[]object[]nomin 2 items
eiCurve[].momentnumberyes> 0
eiCurve[].curvaturenumberyes> 0
momentCapacitynumber | object[]no
lrfdobjectno
lrfd.loads[]object[]yesmin 1 item
lrfd.loads[].type"dead" | "live" | "earthquake" | "impact" | "wind" | "water" | "ice" | "soil-pressure" | "live-roof" | "rain" | "snow" | "temperature" | "special"yes
lrfd.loads[].shearnumberyes
lrfd.loads[].axialnumberno
lrfd.loads[].momentnumberno
lrfd.loads[].distributednumberno
lrfd.cases[]object[]nomin 1 item
lrfd.cases[].namestringyes
lrfd.cases[].factorsobjectyes
lrfd.cases[].phiFlexurenumberyes0 – 1
lrfd.cases[].phiShearnumberno0 – 1
lrfd.phiFlexurenumberno0 – 1
lrfd.phiShearnumberno0 – 1
lrfd.nominalMomentnumberno> 0
lrfd.shearCapacitynumberno> 0

Response fields

FieldTypeDescription
convergedbooleanWhether the nonlinear p-y iteration converged. Treat a non-converged result as unusable.
iterationsnumberIterations the solver needed.
head.deflectionnumberPile-head lateral deflection (m).
head.slopenumberPile-head slope (rad).
head.momentnumberMoment at the head (kN·m).
head.shearnumberShear at the head (kN).
maxMoment.valuenumberLargest-magnitude bending moment along the pile (kN·m).
maxMoment.depthnumberDepth of the maximum moment, from the pile head (m).
maxDeflection.value / .depthnumberLargest-magnitude deflection (m) and its depth (m).
maxShear.value / .depthnumberLargest-magnitude shear (kN) and its depth (m).
equilibrium.residualnumberUnbalanced force after convergence (kN) — a solution-quality check against equilibrium.applied.
equilibrium.appliednumberTotal applied lateral load (kN).
nodes[]object[]The full solution, one entry per finite-difference node from head to tip.
nodes[].depthnumberDepth from the pile head (m).
nodes[].soilDepthnumberDepth below the ground surface (m) — differs from depth when the head is above grade.
nodes[].deflectionnumberLateral deflection y (m).
nodes[].slopenumberSlope dy/dz (rad).
nodes[].momentnumberBending moment (kN·m).
nodes[].shearnumberShear force (kN).
nodes[].soilReactionnumberMobilized soil reaction p (kN/m); opposes the deflection.
sweep[]object[]Present when the request set sweep — one entry per pushover step, each an independent solution at the proportionally scaled head load: shear, moment, headDeflection, headSlope, maxMoment, maxMomentDepth, maxDeflection, converged.
sectionPropertiesobjectPresent when the request set section + material (cracked-section nonlinear EI): the fiber-integrated section's elasticEI (kN·m²), yieldMoment, and plasticMoment (kN·m).

Code examples

A complete, runnable request. Replace YOUR_API_KEY (or set PILECALC_API_KEY in your environment).

POST /v1/lateral
curl https://api.pilecalc.com/v1/lateral \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "unitSystem": "si",
  "pile": {
    "kind": "uniform",
    "length": 15,
    "diameter": 0.61,
    "ei": 143000,
    "groundSurfaceDepth": 0
  },
  "soil": {
    "layers": [
      {
        "model": "soft-clay",
        "top": 0,
        "bottom": 4,
        "gamma": 8.5,
        "c": 24,
        "e50": 0.02
      },
      {
        "model": "sand-reese",
        "top": 4,
        "bottom": 15,
        "gamma": 9.5,
        "phi": 34,
        "k": 16300
      }
    ]
  },
  "head": {
    "kind": "shear-moment",
    "shear": 312,
    "moment": 0
  },
  "axialLoad": 1200,
  "loadType": "cyclic",
  "layering": "direct",
  "increments": 120
}'

The GET variant returns head.deflection,maxMoment.value as a plain-text CSV line — made for Excel's WEBSERVICE() and Sheets' IMPORTDATA() (see Use PileCalc in Excel). Omit fields to get the full JSON response.

Interpreting results

  • Check converged first. If false, the pile is likely failing (soil fully mobilized) or too short — the numbers are not an equilibrium solution.
  • Deflections and moments follow the sign of the applied load; see Units & sign conventions.
  • nodes has increments + 1 entries (default 121). For plots, use nodes[].depth vs. deflection/moment/shear.
  • equilibrium.residual should be small relative to equilibrium.applied; a large residual with converged: true is a red flag worth reporting.

Sizing runs

For load–deflection curves, set sweep (e.g. { "steps": 20 }) instead of sweeping head.shear across calls — the whole pushover curve comes back in sweep[] and costs a single request of your monthly quota.