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
API key optional
Rate Limit
40/hr, 600/hr w/ key
An API key is optional. Add a free one (Dashboard → API Keys — the same keys MCP uses) as Authorization: Bearer ft_... or X-API-Key: ft_... for 600 requests/hour instead of 40. Unknown query parameters are ignored, not rejected, so check a filter's name against the tables below.
What the stored polars cover
- NeuralFoil (large model), one curve per section × Reynolds number × Ncrit.
- Ncrit 1, 4, 9. /polars/{name} returns all three unless you pass ncrit; /polars/search uses Ncrit 9.
- Alpha -20° to +25° in 0.5° steps.
- Re 20k, 50k, 100k, 200k, 300k, 500k, 750k, 1M, 1.5M, 2M, 3M, 5M, 7M, 10M.
- Mach 0 (incompressible). The REST API has no Mach parameter; a mach query is ignored.
MCP Server
NewFoil.tools is also an Model Context Protocol server: connect Claude, Cursor, or any MCP client and your AI assistant can search airfoils, pull polars, run NeuralFoil analysis, optimize profiles, and analyze 3D wings as native tool calls.
Using Claude, ChatGPT or Grok? You don't need to paste an API key — add foil.tools as a connector and sign in to a free account. Setup guide for each assistant →The rest of this section is for wiring MCP into your own client with a key.
Endpoint
Authentication
Required: API key or OAuth
Rate Limit
600 requests/hour
Every tool call needs a credential, including the ones marked “No credits” below: a free API key from your Dashboard (API Keys tab), or a connector sign-in. Without one, initialize and tools/list answer (40 requests/hour per IP) and tools/call returns “Authorization required”. “No credits” means a tool never spends credits, not that it needs no account.
Only optimize_airfoil, analyze_wing and analyze_trim spend credits, from the same balance and monthly free allowance as the browser (analyze_trim has no free allowance). analyze_airfoil and find_airfoil never cost credits. Rates →
Tools
| Tool | Cost | Description |
|---|---|---|
| search_airfoils | No credits | Search the 1,600+ airfoil library by name, family, thickness, camber. Thickness and camber are fractions (0.10 = 10%). |
| get_airfoil | No credits | Geometry summary, CST parameters, and optional Selig coordinates for one airfoil. |
| get_polar | No credits | Stored NeuralFoil polars: a per-Re summary, or CL/CD/CM curves for an Re range, at Ncrit 9 by default (ncrit takes 1, 4 or 9). |
| search_by_operating_point | No credits | Rank airfoils by drag at a target (CL, Re). |
| find_airfoil | No credits | Weighted multi-point selector — scored on drag, Clmax, stall gentleness, pitching moment, efficiency and L/D placement; a point can be marked a constraint (checked, not scored) for a stall or load requirement. Thickness and camber limits are percent (10 = 10%). Parameters below. |
| analyze_airfoil | No credits | NeuralFoil 2D analysis — fresh polars for library or custom geometry. 120 runs/hour per account. Parameters below. |
| optimize_airfoil | Credits | Gradient optimization of CST parameters across weighted operating points. Constraint thickness and camber are fractions (0.10 = 10%). |
| analyze_wing | Credits | 3D wing analysis (AeroBuildup or VLM), and where the wing stalls first. |
| analyze_trim | Credits | Trim an aircraft — wing plus stabiliser about a CG on LiftingLine: trim angle, stabiliser setting, loads, static margin, thrust. Paid-only. Reconnect to see it. |
| search | No credits | Library search in the {id, title, url} shape ChatGPT connectors require. |
| fetch | No credits | One airfoil as a readable record. Pairs with search; required by ChatGPT connectors. |
Units differ between tools. find_airfoil takes thickness and camber in percent (10 = 10%); search_airfoils, the optimize_airfoil constraints and the REST t_min/t_max take fractions (0.10 = 10%).
find_airfoil parameters
| points | Operating points: { re, cl, weight? } scored on drag, Clmax and the rest; or { re, cl, kind: "constraint", load_N? } checked rather than scored (cl must stay within 90% of stall at that Re). 1–20 points; load_N is informational. |
| min_thickness / max_thickness | Percent chord — 10 means 10%. |
| min_camber / max_camber | Percent chord. |
| min_cm / max_cm | Pitching-moment limits; min_cm is the most negative CM allowed. |
| criteria_weights | Decision-matrix weights, keys drag, clmax, stall, cm, efficiency, ld_alpha. Default { drag: 1 }, everything else 0, so { stall: 3 } means drag 1 and stall 3. |
| ncrit | 1, 4, 9 (default 9). |
analyze_airfoil parameters
| name or coords | A library name, or Selig-ordered [x, y] pairs (upper TE→LE, then lower LE→TE), at least 10. |
| re_values | Reynolds numbers (default [500000]). Batch several in one call. |
| alphas | Degrees (default −5 to 15 step 0.5, at most 200). Not blended with a post-stall model — see below. |
| ncrit | Any value (default 9); not limited to the stored three. |
| mach | Accepted, but see the Mach note below. |
| flap / flap_mode | Trailing-edge flap { deflection (degrees, down-positive, ±40), hinge_point (fraction of chord) }. Pass the clean section. "model" (default) leaves CM uncorrected; "geometry" deflects the section so CM responds. |
The full JSON schema for every tool is what tools/list returns.
What analyze_airfoil does and does not model
Mach. Treat results as incompressible (Mach 0). The mach argument is accepted, but on a clean section it is not applied yet, even though each result row echoes the value you sent. A compressibility correction is being worked on; until it ships, don't use these polars above about Mach 0.3.
Post-stall. Alphas are not blended with a 360° post-stall model. Outside roughly ±25° the numbers are raw NeuralFoil extrapolation and not physical, so they can't yet fill a full −180° to +180° table such as a C81 rotor deck.
Connect — Claude Code
claude mcp add --transport http foiltools https://foil.tools/api/mcp --header "Authorization: Bearer ft_YOUR_KEY"
Connect — Claude Desktop / other clients
{
"mcpServers": {
"foiltools": {
"command": "npx",
"args": [
"mcp-remote",
"https://foil.tools/api/mcp",
"--header",
"Authorization: Bearer ft_YOUR_KEY"
]
}
}
}Rate Limiting
All API responses include rate limit headers to help you track your usage:
X-RateLimit-Limit: 40
X-RateLimit-Remaining: 38
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. Hitting the anonymous 40/hour limit? Generate a free API key from your Dashboard and send it as Authorization: Bearer ft_... to raise it to 600/hour — no purchase required.
Endpoints
/api/v1API 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": 40,
"auth": "none",
"authenticated": { "requests_per_hour": 600, "how": "Authorization: Bearer ft_..." }
}
}/api/v1/airfoilsList 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
| Name | In | Required | Description |
|---|---|---|---|
| q | query | No | Fuzzy name search, e.g. "naca 23" or "eppler". |
| family | query | No | Filter by series family, e.g. "NACA 4-digit", "Eppler", "Selig". |
| t_min | query | No | Minimum thickness as a fraction (e.g. 0.10 = 10%). |
| t_max | query | No | Maximum thickness as a fraction. |
| camber_min | query | No | Minimum camber as a fraction. |
| camber_max | query | No | Maximum camber as a fraction. |
| geometry | query | No | Set 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
},
...
]
}/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
| Name | In | Required | Description |
|---|---|---|---|
| name | path | Yes | Airfoil key, e.g. naca2412, e387, s1223. Case-insensitive. |
| format | query | No | Set 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 }
]
}/api/v1/polars/{name}Stored polar rows (CL, CD, CM vs alpha) for one airfoil. Every section is stored at Ncrit 1, 4, 9, and all three come back unless you pass ncrit. Filters cover Re, alpha, CL and Ncrit; there is no CD filter.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| name | path | Yes | Airfoil key, e.g. naca2412, e387, s1223. Case-insensitive. |
| re_min | query | No | Minimum Reynolds number (e.g. 200000). |
| re_max | query | No | Maximum Reynolds number. |
| alpha_min | query | No | Minimum angle of attack in degrees. |
| alpha_max | query | No | Maximum angle of attack in degrees. |
| cl_min | query | No | Minimum lift coefficient. |
| cl_max | query | No | Maximum lift coefficient. |
| ncrit | query | No | Transition criterion: one of 1, 4, 9. Omit it to get all three. |
Example
Request
curl "https://foil.tools/api/v1/polars/naca2412?re_min=500000&re_max=500000&alpha_min=0&alpha_max=8&ncrit=9"
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 },
...
]
}/api/v1/polars/searchRank airfoils by drag at a target operating point, using the Ncrit 9 polars. Finds the closest stored Reynolds bucket per airfoil (or interpolates between the two either side when none is within re_tol), interpolates to the exact target CL in the pre-stall region, and returns matches sorted by ascending CD. There is no thickness or camber filter: narrow by geometry with /api/v1/airfoils, or use the MCP find_airfoil tool for multi-point selection with geometry and CM limits.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| cl | query | Yes | Target lift coefficient, e.g. 0.6. |
| re | query | Yes | Target Reynolds number, e.g. 500000. |
| re_tol | query | No | Fractional Re tolerance for bucket matching (default 0.10 = ±10%). |
| max_cd | query | No | Discard results with CD above this threshold. |
| alpha_max | query | No | Discard results where the interpolated alpha exceeds this value (degrees). |
| family | query | No | Filter to a specific airfoil family, e.g. "Eppler". |
| limit | query | No | Maximum 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
{
"target": { "cl": 0.6, "re": 500000 },
"count": 5,
"results": [
{
"airfoil": "e387",
"re_used": 500000,
"alpha": 3.21,
"cl": 0.6,
"cd": 0.00681,
"cm": -0.0831,
"ld": 88.1
},
...
]
}Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 400 | A required parameter is missing or out of range (e.g. ncrit other than 1, 4 or 9) |
| 404 | Airfoil not found, or no stored polars for it |
| 429 | Rate limit exceeded (40/hour anonymous, 600/hour with an API key) |
| 500 | Internal 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.