Fan selection inside your own program — on a laptop on a building site, without a network.
The DLL answers the same calls as the Selection API, with the same parameters and the same JSON: catalogue, series, products with curves and sound data, and Select fans — the working point computed exactly as in the CloudAir selection software. It reads an encrypted database of the catalogue and a signed licence, both downloaded with your DLL key.
One library for Windows 10+ — 64-bit and 32-bit, about 1.6 MB, no installer, no runtime to install.
Six functions: open, call, free, close, version, last error. Callable from C#, C/C++, Python, VBA, Delphi and anything that loads a DLL.
The same answers as the API. The DLL carries the selection engine of the Selection API and the CloudAir selection software; both are tested to give identical numbers.
Only your part of the catalogue. The database holds the series, products and languages your key covers, nothing else.
menu_bookGuide
Quick start
Get a DLL key (ca_dll_…) from the company whose catalogue you integrate. No key yet? Use Try the demo on the download page.
Download three files at sdk.cloudair.tech/download: the DLL package (DLL-<catalogue>-v1.zip), your database (.cadb) and your licence (.calic). Unzip the package — it has empty folders database\ and licence\ for the other two.
Put all three in the folder of your program's .exe — the DLL from win-x64 for a 64-bit program, win-x86 for a 32-bit one. Details: Where to put the files.
Open with the paths of the database and the licence, then call:
using var dll = CloudAir.Selection.Open(@"C:\MyApp\demo-2026.10.27.cadb", @"C:\MyApp\demo-sdk-download-demo.calic");
string json = dll.Call("select_fan", "{\"volume\":3000,\"pressure\":300}");
The package has a ready console example. In csharp\Example run it with the paths of your two files — it prints the five best fans:
DLL-Demo-Cloudair-v1\
database\ ← copy the .cadb here
licence\ ← copy the .calic here
win-x64\ win-x86\ include\ csharp\ README.txt
cd DLL-Demo-Cloudair-v1\csharp\Example
dotnet run
The example finds the two files in database\ and licence\ by itself. Or give the paths: dotnet run -- C:\Downloads\demo-2026.10.27.cadb C:\Downloads\demo-sdk-download-demo.calic.
menu_bookGuide
The three files
File
What it is
When it changes
cloudair-selection.dll
The library — one for every catalogue, published by CloudAir.
New DLL versions are listed on the download page.
<catalogue>-<version>.cadb
The database: your part of the catalogue, encrypted, named by its version date (e.g. 2026.10.27).
When the catalogue owner publishes a new version — you get an e-mail. Each version works for the period set on your key (3, 6 or 12 months, or until the key ends).
<catalogue>-<company>.calic
Your licence: company, dates, languages and what you may see, signed by CloudAir.
When the owner extends your key or changes what it covers — download it again.
The database opens only with the licence of the same key. A database or licence changed by even one byte is refused.
The previous database version keeps working until its own date, so users can update in their own time.
menu_bookGuide
Where to put the files
The DLL goes next to your program's .exe. The database and the licence go wherever you like — your program gives their paths to ca_open.
Nothing is installed or registered: no installer, no registry, no fixed folder. The simplest setup — everything in one folder:
C:\MyApp\
MyApp.exe
cloudair-selection.dll ← from win-x64 (64-bit program) or win-x86 (32-bit)
acme-2026.10.27.cadb ← the database
acme-sdk-acme.calic ← the licence
using var dll = CloudAir.Selection.Open(
Path.Combine(AppContext.BaseDirectory, "acme-2026.10.27.cadb"),
Path.Combine(AppContext.BaseDirectory, "acme-sdk-acme.calic"));
File
Where
Why
cloudair-selection.dll
The folder of the .exe that loads it.
Windows looks for a DLL next to the program first. For Excel that is not the workbook folder — see VBA below.
.cadb database
Any folder. Next to the .exe, or a data folder such as C:\ProgramData\MyApp\.
Your program passes the full path. A data folder can be written without administrator rights, so the program can replace the database when a new version comes.
.calic licence
Any folder — usually the same as the database.
The same: the path goes to ca_open.
File names do not matter. Rename them as you like, e.g. catalogue.cadb and catalogue.calic — the DLL checks what is inside, not the name. A fixed name makes updates simple: the new database replaces the old file.
Relative paths ("demo.cadb") are read from the current folder of the process, which is not always the .exe folder. Use full paths.
64 or 32 bit follows your program, not Windows: 32-bit Office on 64-bit Windows needs win-x86. The wrong one fails to load (BadImageFormatException in .NET, error 48 in VBA).
Several catalogues — one DLL, a pair of files per catalogue; open each pair with its own ca_open.
Excel / VBA
Excel looks for DLLs next to EXCEL.EXE, not next to the workbook. Keep all three files next to the workbook and switch to its folder before the first call:
ChDrive ThisWorkbook.Path
ChDir ThisWorkbook.Path ' now Excel finds cloudair-selection.dll here
If ca_open(ThisWorkbook.Path & "\catalogue.cadb", ThisWorkbook.Path & "\catalogue.calic", h) <> 0 Then …
Or give the full path in the declaration: Lib "C:\MyTools\cloudair-selection.dll".
functionReference
Functions
Six functions, __stdcall, the same undecorated names in 64-bit and 32-bit builds. Strings are UTF-8. Header: include/cloudair_selection.h.
Function
Description
int ca_open(const char *database, const char *licence, ca_handle **out)
Opens a database with its licence. Returns 0, or an error code — see Errors. Takes 50–200 ms.
Calls an endpoint ("select_fan", "products/6832", "catalog"…) with parameters as a JSON object. Returns JSON {"status", "body"}, or NULL on a library error.
void ca_free(const char *text)
Frees a string returned by ca_call. Always call it.
void ca_close(ca_handle *h)
Closes the database and frees its memory.
const char *ca_version(void)
Version of the library and its engine, e.g. 1.0.0 (engine 2026-10-27, QuickJS-ng 0.17.0).
const char *ca_last_error(void)
Why the last call in this thread failed, for people. Do not free.
swap_horizReference
Calls and answers
Every Selection API endpoint is a DLL call with the same name, parameters and answer. The endpoint goes without /v1; parameters go as a JSON object instead of the query string:
API: GET /v1/select_fan?volume=3000&pressure=300&motor=EC&min.efficiencyStatic=60
DLL: ca_call(h, "select_fan", "{\"volume\":3000,\"pressure\":300,\"motor\":\"EC\",\"min.efficiencyStatic\":60}")
API: GET /v1/products/6832?lang=de
DLL: ca_call(h, "products/6832", "{\"lang\":\"de\"}")
The answer wraps the API body with the status the API would send:
Every call has its own page in the menu on the left — parameters, answer fields and examples, and the panel on the right runs it on the demo catalogue. Variables lists every key used in answers and filters.
errorReference
Errors
Opening — ca_open
Code
Meaning
What to do
1
Bad argument
A path or the handle pointer is missing.
2
Database unreadable
The .cadb file does not exist or cannot be read.
3
Not a database
Not a CloudAir database, or the file is damaged.
4
Database format
An older download — get it again; or a newer DLL is needed.
5
Out of memory
6
Engine error
Should not happen — send ca_last_error() to the catalogue owner.
7
Cannot open
The database decrypted but could not be read.
8
Licence missing
No licence path, or the .calic file cannot be read.
9
Licence signature
The licence was changed, or is not from CloudAir.
10
Licence refuses
LICENCE_EXPIRED, LICENCE_NOT_YET, DATABASE_OTHER_KEY, DATABASE_OTHER_CATALOGUE, DATABASE_EXPIRED (download the current version), CLOCK_BEHIND (the computer date is earlier than the database).
11
Database does not match
The database was changed, or downloaded with another key.
ca_last_error() says it in words, with the reason code where there is one, e.g. LICENCE_EXPIRED: The licence expired on 2027-10-24…
Calls — ca_call
The same refusals as the API, in body.error: NOT_FOUND, FIELD_VALUE, NO_POINT, UNKNOWN_VARIABLE, LANGUAGE_NOT_INCLUDED… — see Responses and errors. Key, address and daily-limit refusals do not exist in the DLL: the licence was checked when the database was opened.
menu_bookGuide
Updates
New database version — the catalogue owner publishes it; the technical e-mail of your key gets a message with the download link. Replace the .cadb next to your program; the licence stays.
New licence — after the owner extends your key or changes what it covers. Download it again.
New DLL — listed on the download page with its version. The database and licence stay.
Automatic updates
Your program can check and download by itself, with your DLL key, when it is online — the same files as the download page:
GET https://selection-api.cloudair.tech/v1/dll → current database version, licence and DLL version
GET https://selection-api.cloudair.tech/v1/dll/database → the current database (.cadb)
GET https://selection-api.cloudair.tech/v1/dll/licence → your licence (.calic)
GET https://selection-api.cloudair.tech/v1/dll/engine → the DLL package (.zip)
Header: X-Api-Key: ca_dll_…
Compare data.database.version with the version you have; download when it is newer.
menu_bookGuide
Threads and memory
One handle, calls in turn. Calls on one handle are queued by the library — safe from several threads, one at a time.
In parallel: open one handle per thread. Each holds its own copy of the database in memory — tens of MB for a large catalogue.
Open once, call many times. Opening takes 50–200 ms; a selection over a whole catalogue 100–300 ms; a product or list a few ms.
Free every answer with ca_free (the .NET wrapper does it for you).
No network. The DLL never connects anywhere; it reads the two files you give it.
codeExamples
Code samples
The same selection in five languages. The .NET wrapper and a C# console example are in the package.
// cloudair-selection.dll next to your program; CloudAirSelection.cs from the package.
using CloudAir;
using var dll = Selection.Open(@"C:\Data\demo-2026.10.27.cadb", @"C:\Data\demo.calic");
string json = dll.Call("select_fan", new Dictionary<string, object>
{
["volume"] = 3000, // m³/h
["pressure"] = 300, // Pa
["limit"] = 5,
});
// {"status":200,"body":{"data":[ { "product": {...}, "point": {...} }, ... ], "meta": {...}}}
try { Selection.Open("old.cadb", "my.calic"); }
catch (SelectionException e) { Console.WriteLine(e.Code + ": " + e.Message); }
#include <stdio.h>
#include "cloudair_selection.h" /* link with cloudair-selection.lib */
int main(void) {
ca_handle *h = NULL;
if (ca_open("demo-2026.10.27.cadb", "demo.calic", &h) != 0) {
fprintf(stderr, "%s\n", ca_last_error());
return 1;
}
const char *json = ca_call(h, "select_fan", "{\"volume\":3000,\"pressure\":300,\"limit\":5}");
if (json) { puts(json); ca_free(json); }
ca_close(h);
return 0;
}
' Module: Excel 64-bit → win-x64 DLL, 32-bit Office → win-x86. Put the DLL next to the workbook.
Private Declare PtrSafe Function ca_open Lib "cloudair-selection.dll" (ByVal db As String, ByVal lic As String, ByRef h As LongPtr) As Long
Private Declare PtrSafe Function ca_call Lib "cloudair-selection.dll" (ByVal h As LongPtr, ByVal ep As String, ByVal params As String) As LongPtr
Private Declare PtrSafe Sub ca_free Lib "cloudair-selection.dll" (ByVal p As LongPtr)
Private Declare PtrSafe Sub ca_close Lib "cloudair-selection.dll" (ByVal h As LongPtr)
Private Declare PtrSafe Function lstrlenA Lib "kernel32" (ByVal p As LongPtr) As Long
Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32" (ByVal cp As Long, ByVal flags As Long, ByVal src As LongPtr, ByVal srcLen As Long, ByVal dst As LongPtr, ByVal dstLen As Long) As Long
' UTF-8 text from the DLL → VBA string
Private Function FromUtf8(ByVal p As LongPtr) As String
Dim n As Long, w As Long
n = lstrlenA(p)
If n = 0 Then Exit Function
w = MultiByteToWideChar(65001, 0, p, n, 0, 0)
FromUtf8 = String$(w, 0)
MultiByteToWideChar 65001, 0, p, n, StrPtr(FromUtf8), w
End Function
Sub SelectFans()
Dim h As LongPtr, p As LongPtr
ChDrive ThisWorkbook.Path: ChDir ThisWorkbook.Path ' so Excel finds the DLL next to the workbook
If ca_open(ThisWorkbook.Path & "\demo.cadb", ThisWorkbook.Path & "\demo.calic", h) <> 0 Then
MsgBox "Cannot open the database": Exit Sub
End If
p = ca_call(h, "select_fan", "{""volume"":3000,""pressure"":300,""limit"":5}")
Range("A1").Value = FromUtf8(p) ' JSON — parse with your JSON module
ca_free p
ca_close h
End Sub
const DLL = 'cloudair-selection.dll';
function ca_open(db, lic: PAnsiChar; out h: Pointer): Integer; stdcall; external DLL;
function ca_call(h: Pointer; ep, params: PAnsiChar): PAnsiChar; stdcall; external DLL;
procedure ca_free(p: PAnsiChar); stdcall; external DLL;
procedure ca_close(h: Pointer); stdcall; external DLL;
function ca_last_error: PAnsiChar; stdcall; external DLL;
var h: Pointer; p: PAnsiChar; json: string;
begin
if ca_open(PAnsiChar(UTF8Encode('demo.cadb')), PAnsiChar(UTF8Encode('demo.calic')), h) <> 0 then
raise Exception.Create(UTF8ToString(ca_last_error));
p := ca_call(h, 'select_fan', '{"volume":3000,"pressure":300}');
json := UTF8ToString(p); // parse with System.JSON
ca_free(p);
ca_close(h);
end;
memoryDLL call
Who am I
CALL"" (empty — who am I)
The first call to make after ca_open.
Tells you which catalogue the database holds, for which company, until when the licence runs and until when this database version opens. Show database.works_until to your users, so they update before it stops working.
In the DLL: ca_call(h, "", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
No parameters
Answer — body (status 200)
Field
Type
Description
api
string
Always CloudAir Selection DLL.
catalogue
string
Name of the catalogue in the database.
company
string
Company the licence was issued to.
licence
object
key (hint), valid_from, valid_to, issued and usage_stats — from the signed licence.
database
object
version (its date), built and works_until — the last day this database version opens.
scope
object
languages of the licence and the language of this answer.
endpoints
array
The calls the DLL answers.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Categories
CALL"categories"
All categories the key sees, as one flat list with parent_id.
Build your own tree, menu or breadcrumbs from it. series counts the series the key sees in each category, so empty branches can be skipped.
In the DLL: ca_call(h, "categories", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Answer — body (status 200)
Field
Type
Description
id
integer
Category ID.
parent_id
integer | null
Parent category — build the tree from it. null at the top.
name
string
Category name in the asked language.
subname
string
Subtitle.
overview
string
Short description.
image
string | null
Full image URL.
series
integer
Series the key sees in this category — skip branches with 0.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Series
CALL"series"
Product families: name, subtitle, categories, image, family-level variables and tags.
In the DLL: ca_call(h, "series", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
category
integer
no
Only series in this category (an id from Categories).
tag
string
no
Tag keys from Tags, comma-separated, e.g. Centrifugal,Phase-1 — only items that have all of them.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
limit
integer
no
Rows per page, 1–1000. Default 100.
offset
integer
no
Rows to skip — with limit, pages through long lists.
Answer — body (status 200)
Field
Type
Description
id
integer
Series ID.
name
string
Series name.
subname
string
Subtitle, e.g. the kind of fan.
overview
string
Short description.
category_ids
integer[]
Categories the series belongs to.
type_ids
integer[]
Series types (features such as EC regulation, belt drive).
formula_id
integer | null
Selection formula. Series with the fan formula take part in Select fans.
image
string | null
Full URL of the series photo.
variables
object
Family-level values keyed as in Variables.
tags
string[]
Tag keys — read them with Tags.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
One series
CALL"series/{id}"
One series with its full description, and the images and files attached to the series (dimension drawings, photos, datasheets…), each with a full download url.
A series outside the key's scope answers 404 — for this key it does not exist.
In the DLL: ca_call(h, "series/{id}", params) — put the number into the call, e.g. "series/6832"; parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
idin the call
integer
yes
Series id from Series or Catalog.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Answer — body (status 200)
Field
Type
Description
…
Everything from Series, plus:
description
string
Full description (may contain simple HTML).
images
array
Photos and drawings: id, type, name, url (full), from (serie).
files
array
Datasheets, manuals, certificates — same shape as images.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Products
CALL"products"
Products with their technical variables — the sizes and models of each series.
Read variables together with Variables to get names and units.
In the DLL: ca_call(h, "products", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
serie
integer
no
Only products of this series.
search
string
no
Part of the model name or catalogue number.
tag
string
no
Tag keys, comma-separated — only products that have all of them. A product carries the tags of its series too.
v. / min. / max.
variables
no
Filters on any variable from Variables: v.phase=1 (equals; v.phase=1,3 — any of), min.powerRated=500, max.speedRated=1500. Combine with &. An unknown variable answers UNKNOWN_VARIABLE.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
limit
integer
no
Rows per page, 1–1000. Default 100.
offset
integer
no
Rows to skip — with limit, pages through long lists.
Filters are keys of the same JSON object: {"v.phase": "3", "min.efficiencyStatic": 60}.
Answer — body (status 200)
Field
Type
Description
id
integer
Product ID.
serie_id
integer
Series of the product.
identifier
string | null
Catalogue or ERP number.
name
string
Model name.
subname
string
Subtitle.
overview
string
Short description.
image
string | null
Full URL of the product photo — or of the series photo when the product has none.
variables
object
Technical values keyed as in Variables, e.g. powerRated, phase, volumeMax.
tags
string[]
Tag keys of the product (the series adds its own).
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
One product
CALL"products/{id}"
Everything about one product in one response: data, description and dimensions; its serie; image_url (the product photo, or the series photo when it has none); curves with sound spectra; accessories attached to it and accessory_of — products it is attached to; images and files with full download urls.
Media come from the product and from its series, marked from: "product" or "serie" — prefer the product's, fall back to the series'. Everything respects the key's scope: an accessory or file the key does not cover is simply not listed.
In the DLL: ca_call(h, "products/{id}", params) — put the number into the call, e.g. "products/6832"; parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
idin the call
integer
yes
Product id from Products or Catalog.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Answer — body (status 200)
Field
Type
Description
…
Everything from Products, plus:
description
string
Full description.
dimension
object
Dimensions from the drawing: letter → value in mm.
serie
object | null
The product's series, as in Series.
image_url
string | null
Product photo, or the series photo when it has none.
curves
array
Performance curves with sound spectra — as in Product curves.
accessories
array
Products attached to this one: id, serie_id, identifier, name, position.
accessory_of
array
Products this one is attached to.
images
array
Photos and drawings of the product and its series: id, type, name, url, from.
files
array
Datasheets and documents — same shape as images.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Product curves
CALL"products/{id}/curves"
Measured performance curves of a product: the measured points (volume m³/h, pressureStatic Pa, power W, speed rpm, …), the fitted polynomials the selection software calculates with, the setting the curve belongs to (Hz frequency, V voltage, VEC EC control voltage, rpm, step, angle blade angle), the measured range x_min–x_max and the sound spectra measured along it.
Polynomial coefficients go in ascending powers of the airflow Q in m³/h: y = A[0] + A[1]·Q + A[2]·Q² + …, one array per quantity (pressureStatic, power, speed, current…). An empty list means the product has no curves in the catalogue.
In the DLL: ca_call(h, "products/{id}/curves", params) — put the number into the call, e.g. "products/6832/curves"; parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
idin the call
integer
yes
Product id.
Answer — body (status 200)
Field
Type
Description
id
integer
Curve ID.
Hz, V, VEC, rpm, step, angle
number | null
The setting the curve was measured at: frequency, voltage, EC control voltage, speed, step, blade angle.
Coefficients per quantity, ascending powers of Q [m³/h]: y = A[0] + A[1]·Q + ….
acoustics
array
Sound spectra along the curve: x (airflow), type, filter, L2_band, L5_band, L6_band (63 Hz … 8 kHz).
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Variables
CALL"variables"
The dictionary for reading variables of products and series: name, symbol, unit, group, rounding step and a description.
symbol and overview may contain simple HTML (<sub>, <p>, <ul>).
In the DLL: ca_call(h, "variables", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
used
boolean
no
1 — only variables that appear in the products and series this key sees.
group
string
no
Only these groups, comma-separated: operation (working-point values computed by selection — volume, pressureStatic, efficiencyStatic, power…), electric, motor, size, regulation, erp, … Every variable says its kind: operation or product.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
operation (computed by Select fans) or product (stored).
precision
number
Rounding step.
min, max
number | null
Allowed limits, when the catalogue sets them.
range
string[]
Allowed values — the keys to use in v. filters.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Tags
CALL"tags"
The dictionary for reading tags of series and products: name in your language, group (type, application, power supply, certificate…), description, icon and colour.
Use it to build filters; filter lists with ?tag=.
In the DLL: ca_call(h, "tags", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
used
boolean
no
1 — only tags carried by the series and products this key sees.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Answer — body (status 200)
Field
Type
Description
key
string
Tag key used in tags and in ?tag=.
name
string
Name in the asked language.
group
string
Group to build filters from: type, application, power supply, certificate…
overview, description
string
Explanations for people.
icon, color
string | null
Material icon name and colour for your interface.
image
string | null
Full image URL.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Select fans
CALL"select_fan"
Fans for a working point, each with the point computed on its curves — the same calculation as the product card of the selection software: regulation, density correction, shaft power, motor efficiency, FEI and sound.
Only fans — series with the selection formula fan — that the key sees. A fan fits when its computed airflow is within the tolerance of the required one and the point lies on its measured curve. Results are ranked by score — static efficiency (100), FEI (50) and power (25), each scaled between the worst and the best result — or by sort. Every result has product with its nominal variables and tags (the same as in Products), point — the computed working point with every variable of group operation (airflow, pressures, powers, efficiencies, speed, frequency, current, FEI, SFP, energy…) plus Lwa and Lpa, keyed as in Variables, regulation (type, mode, control value and unit), sound — octave-band spectra at inlet, outlet and casing, from the product's measured acoustics, or estimated by VDI 3731 from the fan's design and working point when there are no measurements (then sound.estimated is true, as in the selection software) — the stored ErP 2026 compliance and warnings such as MOTOR_OVERLOAD. meta.rejected says why the other candidates fell out.
In the DLL: ca_call(h, "select_fan", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
volume
number
yes
Required airflow, m³/h.
pressure
number
yes
Required pressure, Pa.
pressure_type
string
no
static (default) or total. Total needs the fan's outlet; without it the fan is computed on static pressure.
density
number
no
Air density, kg/m³. Or give temperature instead. Without either: the density the curves were measured at (usually 1.204).
temperature
number
no
Medium temperature, °C — density is computed from it with humidity (%) and altitude (m).
humidity
number
no
Relative humidity, %, for density. Default 0.
altitude
number
no
Altitude above sea level, m, for density. Default 0.
regulation
string
no
automatic (default) — the fan is regulated (frequency, EC voltage, speed) to hit the point; none — it runs on its rated curve; manual — at the setting given in control. A fan that cannot be regulated is computed with none.
control
number
no
Setting for regulation=manual, in the fan's own unit (Hz, V, rpm), clamped to its allowed range.
motor
string
no
Motor supply, comma-separated — the values of motorSupplyType in Variables (e.g. AC, EC, DC). Shortcut for v.motorSupplyType.
regulation_type
string
no
Regulation, comma-separated — the values of regulationType in Variables (inverter, EC, voltage, rotation, step…). Shortcut for v.regulationType.
phase
string
no
1, 3 or 1,3 (shortcut for v.phase).
erp
string
no
2026 — only fans stored as compliant with ErP 2026 (EU 2024/1834).
daily_hours
number
no
Energy calculator: operating hours per day (as on the product card).
working_days
number
no
Energy calculator: working days per year.
energy_cost
number
no
Energy calculator: price of 1 kWh. With the hours and days it fills energyConsumptionPerDay, energyConsumptionPerYear, dailyEnergyCost, annualEnergyCost.
tolerance_min
number
no
Lowest acceptable computed airflow, % of the required one. Default −10.
1 — also points beyond the measured part of the curve (marked OUTSIDE_MEASURED_RANGE).
v. / min. / max.
variables
no
Filters on variables. Product variables (v.phase=3, min.volumeMax=5000) filter the catalogue; working-point variables of group operation (min.efficiencyStatic=60, max.power=800, max.Lwa=75) filter the computed point.
serie
string
no
Only these series, comma-separated ids.
category
integer
no
Only series in this category.
tag
string
no
Tag keys from Tags, comma-separated, e.g. Centrifugal,Phase-1 — only items that have all of them.
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Filters are keys of the same JSON object: {"v.phase": "3", "min.efficiencyStatic": 60}.
Answer — body (status 200)
Field
Type
Description
product
object
id, serie_id, identifier, name, serie, image, nominal variables and tags.
score
number | null
Ranking score 0–100 (with sort=score).
deviation
number
Computed airflow minus required, % of required.
point
object
The computed working point: every variable of group operation (volume, pressureStatic, pressureTotal, power, powerShaft, efficiencyStatic, speed, FEI, SFP, …) plus Lwa and Lpa.
regulation
object
type, mode, control with its unit, the allowed min–max and limited when the setting hit a limit.
sound
object | null
Octave-band spectra at inlet, outlet and casing; estimated: true when computed by VDI 3731.
required, tolerance, considered, fitted, count and rejected — why the other candidates fell out.
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.
Code examples
memoryDLL call
Whole catalogue
CALL"catalog"
Everything the key sees in one response: categories, series, products with variables, and the dictionary of the variables used.
Meant to be fetched once a day and kept — selecting from memory is faster than asking per product.
In the DLL: ca_call(h, "catalog", params); parameters as a JSON object. The answer is {"status": …, "body": …} with body as below — the same as the Selection API.
Parameters (JSON)
Name
Type
Required
Description
brief
boolean
no
1 — names only, without variables: enough for a menu or a tree.
lang
string
no
Language of names and descriptions, e.g. en, pl, de. Falls back to English where a text is missing. A key limited to some languages answers 403 for the others.
Answer — body (status 200)
Field
Type
Description
categories
array
As in Categories.
series
array
As in Series.
products
array
As in Products (names only with brief=1).
variables
object
Dictionary of the variables used, keyed by key (not with brief=1).
Refusals come as {"status": 404, "body": {"error": {"code", "message"}}} — see Errors.