API Documentation

Free, public REST API for airfoil data and aerodynamic polars.

Overview

The Foil.tools API provides programmatic access to our database of >1,600 airfoils and their pre-computed aerodynamic polars across a wide range of Reynolds numbers.

Base URL

https://foil.tools/api/v1

Authentication

None required

Rate Limit

60 requests/hour

Rate Limiting

All API responses include rate limit headers to help you track your usage:

X-RateLimit-Limit: 60

X-RateLimit-Remaining: 58

X-RateLimit-Reset: 1710547200 (Unix timestamp)

When the limit is exceeded, the API returns a 429 status with a JSON body containing the reset time.

Endpoints

GET/api/v1

API discovery endpoint. Returns available endpoints, descriptions, and rate limit info.

Example

Request

curl https://foil.tools/api/v1

Response

{
  "version": "1",
  "base_url": "https://foil.tools/api/v1",
  "endpoints": [ ... ],
  "rate_limit": { "requests_per_hour": 60, "auth": "none" }
}
GET/api/v1/airfoils

List airfoils. Without filters returns all 1,600+ profiles. Supports fuzzy name search and geometric filters. Add geometry=1 to include thickness and camber fields.

Parameters

NameInRequiredDescription
qqueryNoFuzzy name search, e.g. "naca 23" or "eppler".
familyqueryNoFilter by series family, e.g. "NACA 4-digit", "Eppler", "Selig".
t_minqueryNoMinimum thickness as a fraction (e.g. 0.10 = 10%).
t_maxqueryNoMaximum thickness as a fraction.
camber_minqueryNoMinimum camber as a fraction.
camber_maxqueryNoMaximum camber as a fraction.
geometryqueryNoSet to 1 to include thickness and camber values in the response.

Example

Request

curl "https://foil.tools/api/v1/airfoils?family=Eppler&t_min=0.10&t_max=0.14&geometry=1"

Response

{
  "count": 12,
  "airfoils": [
    {
      "name": "Eppler 387",
      "filename": "e387",
      "family": "Eppler",
      "source": "UIUC Database",
      "thickness": 0.0907,
      "camber": 0.0365
    },
    ...
  ]
}
GET/api/v1/airfoils/{name}

Airfoil geometry as Selig-ordered coordinate pairs plus a summary (thickness, camber, TE thickness, LE weight). Add ?format=dat or Accept: text/plain for a raw XFOIL-compatible .dat file.

Parameters

NameInRequiredDescription
namepathYesAirfoil key, e.g. naca2412, e387, s1223. Case-insensitive.
formatqueryNoSet to "dat" to return raw Selig .dat text instead of JSON.

Example

Request

curl https://foil.tools/api/v1/airfoils/e387

Response

{
  "name": "e387",
  "display_name": "Eppler 387",
  "family": "Eppler",
  "summary": {
    "max_thickness": 0.0907,
    "max_camber": 0.0365,
    "te_thickness": 0.0,
    "le_weight": 0.172
  },
  "coordinates": [
    { "x": 1.0, "y": 0.00126 },
    { "x": 0.9982, "y": 0.00268 },
    ...
    { "x": 1.0, "y": -0.00126 }
  ]
}
GET/api/v1/polars/{name}

Aerodynamic polar rows (CL, CD, CM vs alpha) for a specific airfoil. Supports range filters on Re, alpha, CL, and CD.

Parameters

NameInRequiredDescription
namepathYesAirfoil key, e.g. naca2412, e387, s1223. Case-insensitive.
re_minqueryNoMinimum Reynolds number (e.g. 200000).
re_maxqueryNoMaximum Reynolds number.
alpha_minqueryNoMinimum angle of attack in degrees.
alpha_maxqueryNoMaximum angle of attack in degrees.
cl_minqueryNoMinimum lift coefficient.
cl_maxqueryNoMaximum lift coefficient.

Example

Request

curl "https://foil.tools/api/v1/polars/naca2412?re_min=500000&re_max=500000&alpha_min=0&alpha_max=8"

Response

{
  "airfoil": "naca2412",
  "source": "foil.tools",
  "units": { "Re": "dimensionless", "alpha": "degrees", "CL": "dimensionless", "CD": "dimensionless", "CM": "dimensionless" },
  "polars": [
    { "Re": 500000, "Ncrit": 9, "alpha": 0.0, "CL": 0.234, "CD": 0.00634, "CM": -0.0521 },
    { "Re": 500000, "Ncrit": 9, "alpha": 0.5, "CL": 0.289, "CD": 0.00628, "CM": -0.0522 },
    ...
  ]
}
GET/api/v1/polars/search

Rank airfoils by drag at a target operating point. Finds the closest available Reynolds bucket per airfoil, interpolates to the exact target CL in the pre-stall region, and returns matches sorted by ascending CD.

Parameters

NameInRequiredDescription
clqueryYesTarget lift coefficient, e.g. 0.6.
requeryYesTarget Reynolds number, e.g. 500000.
re_tolqueryNoFractional Re tolerance for bucket matching (default 0.10 = ±10%).
max_cdqueryNoDiscard results with CD above this threshold.
alpha_maxqueryNoDiscard results where the interpolated alpha exceeds this value (degrees).
familyqueryNoFilter to a specific airfoil family, e.g. "Eppler".
limitqueryNoMaximum number of results to return (default 20, max 100).

Example

Request

curl "https://foil.tools/api/v1/polars/search?cl=0.6&re=500000&max_cd=0.012&limit=5"

Response

{
  "query": { "cl": 0.6, "re": 500000, "re_tol": 0.1, "max_cd": 0.012 },
  "count": 5,
  "results": [
    {
      "airfoil": "e387",
      "re_used": 500000,
      "alpha": 3.21,
      "CL": 0.6,
      "CD": 0.00681,
      "CM": -0.0831
    },
    ...
  ]
}

Status Codes

CodeDescription
200Success
404Airfoil not found
429Rate limit exceeded (60 requests/hour)
500Internal server error

CORS

All /api/v1/* endpoints support cross-origin requests. The API returns Access-Control-Allow-Origin: * so you can call it directly from browser-based applications.