Overview

A free ductulator API for HVAC duct sizing calculations. Submit airflow (CFM) and friction rate or velocity, get back round and rectangular duct dimensions. All requests are GET. No authentication required. Returns XML by default for Excel compatibility, or JSON for use in code.

Endpoint: https://rysercad.com/api.php

Parameters

Parameter Type Description
cfm number required Airflow in cubic feet per minute
friction number optional Friction rate in in.w.g./100ft. Default: 0.1. Used when mode=friction.
velocity number optional Air velocity in FPM. Required when mode=velocity.
mode string optional friction or velocity. Default: friction.
height number optional Fix rectangular duct height in inches and solve for width. If omitted, height is calculated automatically.
format string optional xml (default) or json. Use json for Python, Google Apps Script, or any HTTP client.

Response Fields

Field Unit Description
cfmCFMAirflow (echoed from input)
roundDiameterinRound duct diameter
roundAreasq ftRound duct cross-sectional area
roundVelocityFPMAir velocity in round duct
roundFrictionin.w.g./100ftFriction rate in round duct
rectWidthinRectangular duct width
rectHeightinRectangular duct height
rectAreasq ftRectangular duct cross-sectional area
rectVelocityFPMAir velocity in rectangular duct
rectEquivDiainEquivalent diameter of rectangular duct
rectFrictionin.w.g./100ftFriction rate in rectangular duct
aspectRatioWidth-to-height ratio

Excel Usage

Retrieve the full XML response in one cell, then extract individual fields with FILTERXML().

Basic — friction mode:

=WEBSERVICE("https://rysercad.com/api.php?cfm="&A1&"&friction="&B1)

Velocity mode:

=WEBSERVICE("https://rysercad.com/api.php?cfm="&A1&"&mode=velocity&velocity="&B1)

Fixed height:

=WEBSERVICE("https://rysercad.com/api.php?cfm="&A1&"&friction="&B1&"&height="&C1)

Extract round diameter from result in D1:

=FILTERXML(D1,"//roundDiameter")

Extract and round up rect width:

=ROUNDUP(FILTERXML(D1,"//rectWidth"),0)

Suggested column layout:

A: CFM B: Friction C: Height Override D: WEBSERVICE (raw XML) E: Round Dia F: Rect Width
400 0.1 12 =WEBSERVICE(...) =FILTERXML(D1,"//roundDiameter") =ROUNDUP(FILTERXML(D1,"//rectWidth"),0)
C (height override) is optional. Leave blank for automatic sizing, enter a value to fix the height and solve for width.

Rate Limiting

60 requests per minute per IP address. Exceeding this returns an error in the response.

Google Sheets Usage

Use IMPORTXML() to pull individual fields directly — no intermediate cell needed.

Round diameter:

=IMPORTXML("https://rysercad.com/api.php?cfm="&A1&"&friction="&B1,"//roundDiameter")

Rect width with fixed height:

=IMPORTXML("https://rysercad.com/api.php?cfm="&A1&"&friction="&B1&"&height="&C1,"//rectWidth")

JSON Usage

Add &format=json to get a JSON response for use in Python, JavaScript, or any HTTP client.

Example request:

https://rysercad.com/api.php?cfm=400&friction=0.1&format=json

Example response:

{
  "success": true,
  "data": {
    "cfm": "400",
    "roundDiameter": "9.8",
    "roundArea": "0.52",
    "roundVelocity": "764",
    "roundFriction": "0.100",
    "rectWidth": "16.2",
    "rectHeight": "8",
    "rectArea": "0.90",
    "rectVelocity": "445",
    "rectEquivDia": "9.8",
    "rectFriction": "0.100",
    "aspectRatio": "2.0"
  }
}

Python example:

import requests

r = requests.get("https://rysercad.com/api.php", params={
    "cfm": 400,
    "friction": 0.1,
    "format": "json"
})
data = r.json()["data"]
print(data["roundDiameter"], data["rectWidth"], data["rectHeight"])

Error Response

XML error:

<duct><error>CFM must be greater than 0.</error></duct>

JSON error:

{"success": false, "error": "CFM must be greater than 0."}

Check for XML errors in Excel with: =FILTERXML(D1,"//error")