RotorLab logo RotorLabDocs

API quickstart

The RotorLab API is a key-authenticated HTTP API over the same physics engine the app uses. You can analyze any build (multirotor, fixed wing, or VTOL), work out radio link budgets and center of gravity, read the parts catalog and airframe types, manage your saved builds, run log forensics, and file flight records, all from your own scripts and applications.

Every endpoint lives under one base URL:

https://rotorlab.app/api/v1

Get a key#

  1. Sign in and open My account, then the API access section.
  2. Type a label in the What will use this key? field and press Create API key.
  3. Copy the key immediately. It is displayed once, at creation, and only its SHA-256 hash is stored. The key looks like rl_....

Issue a separate named key for each integration, so revoking a compromised key does not affect the others. The list in API access shows each key's prefix, label, creation date, and when it was last used. Revoke removes one key; Revoke all keys removes every key on the account at once. See API access for the full key management page.

Device credentials

Ground stations and other equipment use a device credential instead of a personal key. A device credential belongs to your organization rather than to an individual, so it stays valid after the person who created it leaves, and it reaches only the flight, checklist, pilot roster, and aircraft registry endpoints.

Authenticate#

Send the key as a bearer token. The header X-API-Key is also accepted.

Authorization: Bearer rl_your_key

or

X-API-Key: rl_your_key

A missing or invalid key returns 401 with {"error": "Invalid or missing API key"}.

Your first call#

GET /version is free and unmetered, so it is the right endpoint to confirm your key works:

curl -H "Authorization: Bearer rl_your_key" \
  https://rotorlab.app/api/v1/version
{"name": "RotorLab", "version": "1.59.0", "author": "RotorLab.app"}

Then read your own quota with GET /usage, also free:

curl -H "Authorization: Bearer rl_your_key" \
  https://rotorlab.app/api/v1/usage

The response reports limit (requests per day from your plan), used, remaining, credits, the current UTC day, and a key object with your key's prefix, creation date, and last use.

Metering in brief#

  • Every request spends one unit, except version and usage (so a blocked client can still read its own status) and the flight-record endpoints (flights, checklists, pilots, aircraft), because filing your own records is never metered.
  • Your plan sets a daily quota, spent first. It resets at 00:00 UTC.
  • Once the quota is gone, requests draw from your credit balance. Credits come included with some plans, can be granted by an admin, or can be purchased from My account.
  • When both are exhausted, the API returns 429 with a Retry-After header giving the seconds until the daily reset.
  • Every metered response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Credits, so your client always knows where it stands without spending a request.
  • A key whose trial or billing period has ended is refused with 403 on metered endpoints; version and usage stay open.

Worked example: analyze a build#

POST /analyze takes a build-parameters object and returns full performance results. Every field is optional; anything you leave out falls back to the example profile's defaults, so a minimal body is enough to get numbers.

curl#

curl -X POST https://rotorlab.app/api/v1/analyze \
  -H "Authorization: Bearer rl_your_key" \
  -H "Content-Type: application/json" \
  -d '{"airframe_type":"Quad X","motor_count":4,"prop_diameter_in":7,"motor_kv":1700}'

Python (standard library only)#

import json
import urllib.request

BASE = "https://rotorlab.app/api/v1"
KEY = "rl_your_key"

body = json.dumps({
    "airframe_type": "Quad X",
    "motor_count": 4,
    "prop_diameter_in": 7,
    "motor_kv": 1700,
}).encode("utf-8")

req = urllib.request.Request(
    f"{BASE}/analyze", data=body, method="POST",
    headers={"Authorization": f"Bearer {KEY}",
             "Content-Type": "application/json"})

with urllib.request.urlopen(req) as resp:
    result = json.load(resp)

out = result["out"]
print(f"AUW {out['auw_g']:.0f} g, TWR {out['twr']:.2f}, hover {out['hover_min']:.1f} min")

for level, message in result["checks"]:
    print(f"  [{level}] {message}")

Reading the response#

KeyWhat it holds
outHeadline numbers: auw_g, twr, hover_min, currents, top speed, sag and thermal margins, and for winged builds stall_speed_kmh, cruise_speed_kmh, climb_rate_ms, wing_loading_n_m2
chartsInline SVG chart strings, ready to embed
checks[level, message] pairs, where level is ok, warn, or bad
lintThe same findings as checks, machine readable
platformResolved platform description: airframe class, motor groups, layout
cgCenter of gravity and balance result

Which fields appear in out depends on the airframe: multirotors report hover figures, wings report stall, cruise, and climb, and VTOLs report both. Send a fixed-wing or VTOL airframe_type with your wing dimensions and the same endpoint returns the winged figures. GET /airframes lists every supported type.

Where to go next#