API Reference
Calculate Endpoint

Calculate Endpoint

Calculate pool chemical dosing recommendations based on current water readings.

Request

POST /api/calculate/
Content-Type: application/json

No authentication required.

Request Body

FieldTypeRequiredDescription
formula_idstringYesThe formula to use for calculations. See valid formula IDs.
readingsobjectYesCurrent pool water readings as {reading_id: value}. See valid reading IDs.
poolobjectYesPool information. See pool object.
target_levelsarrayNoOverride default target ranges. See target levels.
substitutionsobjectNoOverride default treatments for specific readings. See substitutions.

Pool Object

FieldTypeRequiredDescription
gallonsnumberYesPool volume in gallons.
water_typestringNoSanitization method. One of: chlorine, salt_water, bromine, minerals, copper, ozone, uv.
wall_typestringNoPool wall material. One of: vinyl, plaster, fiberglass, concrete, pebble. Affects calcium hardness targets for concrete/plaster/pebble pools.

Target Levels

An array of objects to override default target ranges:

FieldTypeDescription
idstringThe reading ID to override (e.g. "fc", "ph").
minnumberMinimum target value.
maxnumberMaximum target value.

Substitutions

A mapping of reading ID to treatment overrides:

{
  "fc": { "up": "dichlor" },
  "ph": { "down": "sodium_bisulfate" }
}
FieldTypeDescription
upstringTreatment ID to use when raising this reading.
downstringTreatment ID to use when lowering this reading.

Response

{
  "actions": [
    {
      "readings": [
        { "id": "fc", "name": "Free Chlorine", "short_name": "Free Chlorine", "units": "ppm" }
      ],
      "type": "raise",
      "treatment": {
        "id": "calc_hypo",
        "name": "Chlorine Granules",
        "type": "dryChemical",
        "concentration": 67,
        "description": "Pre-dissolve in a bucket of water and pour into pool.",
        "waitMinutes": 15
      },
      "ounces": 3.58,
      "treatment_options": [
        { "id": "chlorine_tablets", "name": "Chlorine Tablets", "type": "task", "concentration": 100, "description": "...", "waitMinutes": 60 },
        { "id": "calc_hypo", "name": "Chlorine Granules", "type": "dryChemical", "concentration": 67, "description": "...", "waitMinutes": 15 },
        { "id": "na_hclo", "name": "Liquid Chlorine", "type": "liquidChemical", "concentration": 10, "description": "...", "waitMinutes": 60 }
      ]
    }
  ]
}

Action Object

FieldTypeDescription
readingsarrayThe readings this action addresses. Each has id, name, short_name, units.
typestringOne of "raise", "lower", "special", "warning".
treatmentobjectThe recommended treatment. See treatment object.
ouncesnumberAmount in ounces. For "warning" type: the delta from ideal (negative = too low, positive = too high). For "special" wait actions: the number of minutes to wait.
treatment_optionsarrayAlternative treatments the user can choose from.

Treatment Object

FieldTypeDescription
idstringTreatment identifier.
namestringDisplay name.
typestringOne of "dryChemical", "liquidChemical", "task", "calculation", "warning", "wait".
concentrationnumberPercent active ingredient (0-100).
descriptionstringInstructions for applying the treatment.
waitMinutesnumberMinutes to wait after applying before the next treatment.
taskNamestring(Optional) Short name for task-type treatments.

Formula IDs

IDDescription
chlorine_cal_hypoStandard chlorine pools (calcium hypochlorite). The most common formula.
saltSalt water / salt chlorine generator pools.
bromineBromine-sanitized pools and hot tubs.
mineralsMineral sanitization system pools.

Reading IDs

IDNameUnitsTypical RangeDescription
fcFree Chlorineppm0 - 10Active sanitizer level. Target: 1-3 ppm.
tcTotal Chlorineppm0 - 10Free + combined chlorine.
ccCombined Chlorineppm0 - 1Calculated as TC - FC. Indicates chloramines.
phpH6.0 - 8.5Water acidity/alkalinity. Target: 7.2-7.6.
taTotal Alkalinityppm0 - 300pH buffer capacity. Target: 80-120 ppm.
cyaCyanuric Acid (CYA)ppm0 - 300UV stabilizer for chlorine. Target: 30-50 ppm.
chCalcium Hardnessppm0 - 800Calcium content. Target: 175-225 ppm (200-275 for plaster/concrete).
saltSaltppm0 - 5000Salinity level for salt water pools. Target: 2700-3400 ppm.
broBromineppm0 - 20Bromine sanitizer level. Target: 3-5 ppm.
copperCopperppm0 - 3Copper ion level. Target: 0.2-0.4 ppm.
disoxDissolved Oxygenppm0 - 20Dissolved oxygen level.

Treatment IDs

IDNameType
calc_hypoChlorine GranulesdryChemical
na_hcloLiquid ChlorineliquidChemical
chlorine_tabletsChlorine Tabletstask
dichlorDichlordryChemical
bromineBrominedryChemical
cal_chlorHardness IncreaserdryChemical
soda_ashSoda Ash (pH Up)dryChemical
m_acidMuriatic Acid (pH Down)liquidChemical
sodium_bisulfateDry Acid (pH Down)dryChemical
baking_sodaBaking Soda (TA Up)dryChemical
alk_increaserAlkalinity IncreaserdryChemical
ph_increaserpH IncreaserdryChemical
cyaStabilizer (CYA)dryChemical
saltPool SaltdryChemical
swg_upIncrease SWG Outputtask
shockShockdryChemical
drainDrain & Refilltask

Examples

Basic Request

curl -X POST https://api.poolcloud.com/api/calculate/ \
  -H "Content-Type: application/json" \
  -d '{
    "formula_id": "chlorine_cal_hypo",
    "readings": {
      "fc": 0,
      "ph": 7.2,
      "ta": 80,
      "tc": 0,
      "cya": 0,
      "ch": 0
    },
    "pool": {
      "gallons": 10000,
      "water_type": "chlorine",
      "wall_type": "plaster"
    }
  }'

With Substitutions

Use dichlor instead of the default chlorine treatment:

curl -X POST https://api.poolcloud.com/api/calculate/ \
  -H "Content-Type: application/json" \
  -d '{
    "formula_id": "chlorine_cal_hypo",
    "readings": { "fc": 1, "ph": 7.4 },
    "pool": { "gallons": 15000 },
    "substitutions": {
      "fc": { "up": "dichlor" }
    }
  }'

With Custom Target Levels

Override the default target range for free chlorine:

curl -X POST https://api.poolcloud.com/api/calculate/ \
  -H "Content-Type: application/json" \
  -d '{
    "formula_id": "chlorine_cal_hypo",
    "readings": { "fc": 2, "ph": 7.5 },
    "pool": { "gallons": 20000 },
    "target_levels": [
      { "id": "fc", "min": 3, "max": 5 }
    ]
  }'

Error Responses

400 — Bad Request

Returned when the formula runner encounters an error (e.g. invalid formula_id).

{ "error": "Calculation failed: Unknown formula_id \"invalid\". Valid IDs: chlorine_cal_hypo, salt, bromine, minerals" }

422 — Validation Error

Returned when the request body fails schema validation (e.g. missing required fields).

{
  "error": "Validation error",
  "detail": "...",
  "field_errors": [...]
}

504 — Timeout

Returned if the calculation takes longer than 10 seconds.

{ "error": "Calculation timed out" }