API reference for LLMs¶
This page is written for an AI agent calling MagicON AI directly. It is not the human manual — for that, start at the documentation home.
The endpoints, rate limits and worked-example figures below were verified against the live production API on 2026-09-08.
In one paragraph¶
MagicON AI exposes a set of RF and PCB design engines over plain HTTPS. They are deterministic solvers over a catalog of 2,400+ real RF components: you send a design point, you get a complete result back in one response. No account, no API key, no OAuth, no job queue. The engines are the same ones behind the web app — there is no separate "API version" of the maths.
Connecting¶
Base URL
Authentication: none for every engine listed on this page. Send no
Authorization header. (CAD export routes — KiCad, ODB++, Gerber — do require a
signed-in user and are not covered here.)
Headers: Content-Type: application/json. That is the whole list.
Transport: HTTPS only. There is no MCP server yet. If you are an MCP-capable client, you call these as ordinary HTTP requests.
Schemas: the full machine-readable request and response schema for every
route is at
/openapi.json.
This page gives you orientation and guarantees; the OpenAPI document gives you
field-level detail, and it is generated from the running code so it cannot drift.
The engines¶
Every path below is POST, anonymous, and was confirmed reachable in production.
The rate limit is per calling IP address.
| Engine | Endpoint | Limit | First required field |
|---|---|---|---|
| Transmit chain design | /api/rf-chain/design-sync |
5/min | (none enforced — see trap 3) |
| Transmit chain design (streaming) | /api/rf-chain/design |
5/min | params, streamed over SSE |
| Compare chain alternatives | /api/rf-chain/design-multi |
30/min | params |
| Receiver — compute only | /api/receiver |
60/min | stages |
| Receiver — pick parts and compute | /api/receiver/design |
30/min | rfFrequencyHz |
| T/R module — compute only | /api/tr-module |
60/min | (see note below) |
| T/R module — assemble and compute | /api/tr-module/design |
15/min | frequencyGhz |
| Link budget cascade | /api/link-budget/compute |
120/min | stages |
| Stackup solver | /api/solver/solve |
30/min | layer_count |
| Thermal analysis | /api/stackups/thermal-analysis/preview |
10/min | analysis_input |
| PDN impedance | /api/pdn/analyze |
30/min | plane_pairs |
| Regulatory compliance | /api/compliance/check |
1000/hour | layers |
Anything without its own limit falls back to the global default of 1000 requests per hour. Exceeding a limit returns HTTP 429.
Choosing between the two receiver routes — this is the mistake agents make
most often. POST /api/receiver is the pure-maths path: you supply every cascade
stage and it computes. POST /api/receiver/design is the intent path: you supply
a frequency and it picks real catalog parts and then computes. If you only know
"X-band, 10 MHz bandwidth", you want the second one. The same split exists for
T/R modules.
A complete worked example¶
A real design point, and the figures production actually returned for it.
Request
curl -X POST https://api.pcbgenerator.com/api/receiver/design \
-H "Content-Type: application/json" \
-d '{"rfFrequencyHz": 9400000000, "bandwidthHz": 10000000, "requiredSnrDb": 12}'
Response — 200, sub-second, about 36 KB. These are the headline figures:
| Field | Value |
|---|---|
cascade.totalGainDB |
31.65 |
cascade.cascadedNfDB |
1.7798 |
cascade.sensitivityDbm |
−90.22 |
cascade.noiseFloorDbm |
−104.0 |
cascade.cascadedOip3Dbm |
27.24 |
cascade.sfdrDb |
65.21 |
needsPartFlags |
[] — every slot filled |
And the parts it chose, one per slot:
| Slot | Part |
|---|---|
limiter |
TGL2209-SM |
lna |
BFP840ESD |
imageFilter |
B095MB1S |
mixer |
CMD183C4 |
localOscillator |
ADF5611 |
ifFilter |
CBP2-1090C+ |
ifAmp |
PHA-23LN+ |
digitalStepAttenuator |
HMC1119 |
connector |
SMA-J-P-H-ST-EM1 |
substrate |
RO3003-50ohm-MS |
Top-level response keys: cascade, parts, stages, frequencyPlan,
adcInterface, interference, analysis, bom, alternatives,
needsPartFlags, assumptions, warnings.
What we stand behind, and what we don't¶
This is the part that matters most, and it is the reason this page exists separately from the manual.
Numbers in the response are computed. They come from published component data and from solvers, not from a language model. Nothing on the response side is generated text dressed up as a figure.
Numbers in your request are yours. The engines have no way to tell whether a value you sent was stated by your user or invented by you. They will compute faithfully from whatever you send. If you pass a noise figure your user never gave you, you will get a precise, authoritative-looking, wrong answer — and it will be wrong because of your input, not our maths. Pass through what your user actually said.
Read assumptions before reporting a result. When the engine has to choose
something you did not specify, it says so in plain language. The example above
returned, among others:
"IF of 1128.0 MHz was CHOSEN BY THE ENGINE (~12% of RF, floored at 5x the signal bandwidth), not supplied. Pass an explicit IF to override."
If you report the result without that sentence, you are presenting our choice as your user's decision.
An empty slot is declared, never filled. If no catalog part can satisfy a
position in the chain, it comes back named in needsPartFlags and the slot stays
empty. We do not substitute a plausible part. An empty needsPartFlags means
every slot was genuinely filled.
Check warnings too. They carry things like regulatory overages,
compression, and stress-rating verdicts. The example above returned six.
Errors¶
| Status | Meaning | What to do |
|---|---|---|
| 422 | Your request is missing or has a malformed field | Read detail — it names the field, e.g. "rfFrequencyHz is required to choose parts for a receiver". Ask your user, do not invent the value. |
| 429 | Rate limit exceeded | Back off; the limits are in the table above. |
| 500 | Our fault | Retry once, then report it. A malformed design point is a 422, never a 500. |
Error bodies are {"detail": "..."} — either a plain sentence from the engine,
or FastAPI's structured validation list when a typed field is missing.
Things that will trip you up¶
- Frequencies are in hertz on some routes and gigahertz on others. The
receiver takes
rfFrequencyHz(9400000000); the T/R module takesfrequencyGhz(9.4). Read the field name, not the number. POST /api/rf-chain/designstreams. It returns Server-Sent Events, not a JSON body. Use/api/rf-chain/design-syncif you want one response.- The
{}request is not a validity test./api/rf-chain/design-syncand/api/tr-moduleboth answer 200 to an empty body with null-filled results. A 200 does not by itself mean you asked a meaningful question. - Nothing persists. Every call is independent. There is no session, no project id, and no result to fetch later. If a second call needs a figure from the first, carry it yourself.
- There is nothing to poll. Every engine returns its complete result in the
same response. If you find yourself looking for a
job_id, you are looking for an API we do not have.
Related¶
- How we ground our numbers — the same discipline, explained for humans.
- RF chain design rules — the constraints the selection engine enforces.
- llms.txt — the site index for agents.