---
title: "Run Thermal Analysis"
method: POST
path: "/api/stackups/{stackup_id}/thermal-analysis"
tags: ["stackups"]
---

# Run Thermal Analysis

`POST /api/stackups/{stackup_id}/thermal-analysis`

## Request

- Base URL: `https://api.pcbgenerator.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.pcbgenerator.com/api/stackups/{stackup_id}/thermal-analysis`
- Auth: none declared

Run full thermal analysis for a saved stackup.

## Path parameters

- `stackup_id` string, required

## Request body

- ThermalAnalysisRequest
  - `via_config` ThermalViaConfig: Configuration for a thermal via or via array.
    - `via_diameter_mm` number, required: Via drill diameter in mm
    - `via_pitch_mm` number, required: Center-to-center pitch in mm
    - `via_array_rows` integer, required: Number of rows in the via array
    - `via_array_cols` integer, required: Number of columns in the via array
    - `copper_fill` 'filled' | 'plated', required: Via fill type: filled (solid copper) or plated (annular ring)
    - `plating_thickness_mm` number, required: Plating thickness in mm
    - `board_thickness_mm` number, required: Total board thickness in mm
  - `analysis_input` ThermalAnalysisInput, required: Input parameters for a thermal analysis run.
    - `power_w` number, required: Power dissipation in watts
    - `ambient_c` number, required: Ambient temperature in degrees Celsius
  - `stackup_layers` ThermalStackLayer[], nullable
    - `name` string, required
    - `rth` number
    - `material` string, required
    - `thickness_mm` number, required
    - `layer_type` 'copper' | 'core' | 'prepreg' | 'dielectric', nullable
    - `tg_c` number, nullable
  - `source_area_mm2` number, nullable
  - `pour_area_mm2` number, nullable
  - `copper_thickness_mm` number, nullable
  - `board_length_mm` number, nullable
  - `board_width_mm` number, nullable
  - `copper_coverage_top_pct` number, nullable
  - `copper_coverage_bottom_pct` number, nullable
  - `copper_coverage_source` 'assumed' | 'user', nullable
  - `layer_count` integer, nullable
  - `effective_cte_z_ppm` number, nullable
  - `delta_t_c` number, nullable
  - `heatsink` HeatsinkPath: A user-STATED heatsink the junction heat leaves through (thermal-heatsink-resistance). ⛔ Every field is a statement, never a default: no MagicON engine computes a heatsink's or an airframe spreader's θsa, and the mount changes Tj by the whole board path, so a partial object is refused naming the missing field rather than filled in. θcs may be an explicit 0 (a stated perfect interface); θsa may not — a zero θsa is the "infinite heatsink" and would read as a real part. - ``mount="board"`` (SMT PA on a drone airframe spreader): die → θjc → pad → spreading → via array → board bottom → θcs → θsa → air. - ``mount="flange"`` (bolt-down GaN): die → θjc → flange → θcs → θsa → air; the PCB is not in the heat path.
    - `theta_cs_c_per_w` number, required: Case/board-to-sink interface resistance (pad/grease/TIM), °C/W
    - `theta_sa_c_per_w` number, required: Sink (or airframe spreader) to ambient resistance, °C/W
    - `mount` 'board' | 'flange', required: board: heat crosses the PCB into the sink; flange: bypasses the PCB

## Response `200`

Successful Response

- ThermalAnalysisSummary: Top-level summary combining all thermal analysis results.
  - `via_result` ThermalViaResult: Result of thermal via resistance calculation.
    - `single_via_rth` number, required
    - `array_rth` number, required
    - `array_area_mm2` number, required
    - `equivalent_conductivity` number, required
    - `via_count` integer, required
  - `stack_result` ThermalStackResult: Result of junction-to-ambient thermal chain analysis.
    - `total_rth` number, required
    - `junction_temp_c` number, required
    - `layer_results` ThermalStackLayer[], required
      - `name` string, required
      - `rth` number
      - `material` string, required
      - `thickness_mm` number, required
      - `layer_type` 'copper' | 'core' | 'prepreg' | 'dielectric', nullable
      - `tg_c` number, nullable
    - `dominant_bottleneck` string, required
  - `spreading_result` CopperPourSpreadingResult: Result of copper pour spreading resistance calculation.
    - `spreading_rth` number, required
    - `effective_area_mm2` number, required
    - `tau` number, required
  - `coupling_2d` TwoDCouplingResult: 2-D inner-layer thermal-coupling correction (Option-1 analytical). The 1-D headline Tj (``calculate_localized_junction_temp``) only spreads heat in the source-layer copper pour. Real inner copper planes spread the same source heat laterally too. This applies Kennedy spreading per inner copper layer (each layer's net copper area as ``pour_area``) and combines those lateral paths in PARALLEL with the source pour, lowering the effective spreading resistance and yielding a (≤ 0) Tj correction delta. It is a delta ALONGSIDE the 1-D number — the 1-D headline is never replaced.
    - `junction_temp_1d_c` number, required
    - `junction_temp_2d_c` number, required
    - `delta_tj_c` number, required
    - `spreading_rth_1d` number, required
    - `spreading_rth_2d` number, required
    - `inner_layer_count` integer, required
    - `inner_layers` InnerLayerSpreadingResult[]
      - `name` string, required
      - `pour_area_mm2` number, required
      - `spreading_rth` number, required
  - `barrel_stress` ViaBarrelStressResult: Result of via barrel thermo-mechanical stress analysis.
    - `axial_strain` number, required
    - `axial_stress_mpa` number, required
    - `fatigue_cycles` integer, required
    - `meets_ipc_class_2` boolean, required
    - `meets_ipc_class_3` boolean, required
  - `warpage` WarpagePredictionResult: Result of board warpage prediction. ⛔ `copper_coverage_source` is the PROVENANCE of the only input that moves this model, and it gates the pass/fail verdict — never drop it when building or forwarding a result. Deflection is a function of ``|top - bottom|`` coverage alone (``warpage.predict_warpage``), and nothing in this repo measures per-side copper coverage, so a caller that supplied no coverage of its own gets the number with ``"assumed"`` and NO IPC verdict: ``recommendations._warpage_recommendation`` declines, and the frontend badges it "not assessed". "user" means a person (or an agent tool arg) actually supplied the coverage, and the verdict is asserted. Default is ``"assumed"`` deliberately — a caller that forgets the field must fall back to withholding a verdict, not to asserting one.
    - `max_deflection_mm` number, required
    - `deflection_pct_diagonal` number, required
    - `meets_ipc_6012_bow_twist` boolean, required
    - `copper_balance_ratio` number, required
    - `symmetry_score` number, required
    - `copper_coverage_source` 'assumed' | 'user'
  - `resin_flow` ResinFlowEstimate[]
    - `layer_name` string, required
    - `flow_ratio` number, required
    - `starved_risk` boolean, required
    - `bleed_risk` boolean, required
    - `recommendation` string, required
  - `findings` string[]
  - `recommendations` ThermalRecommendation[]
    - `severity` 'info' | 'warning' | 'error' | 'critical', required
    - `category` 'via_array' | 'warpage' | 'barrel_fatigue' | 'tj_margin' | 'power_density' | 'resin_flow' | 'device_tj_limit', required
    - `title` string, required
    - `detail` string, required
    - `current_value` number, nullable
    - `suggested_value` number, nullable
    - `unit` string, nullable
  - `via_array_rows` integer, nullable
  - `via_array_cols` integer, nullable
  - `via_array_source` 'auto_optimized', nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/pcbgenerator/apis/pcb-stackup-generator-api.md) · [All operations](https://skmtc.dev/pcbgenerator/apis/pcb-stackup-generator-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pcbgenerator/apis/pcb-stackup-generator-api/revisions/b6084b3ace32?raw)
