Documentation sections
Simulation jobs
The calculators answer in one request. The simulators do not (a full-wave solve runs for minutes to hours), so they are submitted as jobs and polled. Every job type publishes its parameter contract at /api/py/v1/jobs/types: type, unit, range or options, default and requiredness for every parameter, and the limits of your plan. The browser form is built from that document and the worker validates against it, so read it rather than typing parameter names from this page.
Endpoints
| Endpoint | What it does | Credential |
|---|---|---|
| GET /api/py/v1/jobs/types | Every simulation job type, its tiers, time ceiling, limits and uploads. | None |
| GET /api/py/v1/jobs/types/{job_type} | One job type's parameter contract, as JSON Schema. | None |
| POST /api/py/v1/jobs/estimate | What a job would cost and how long it would run, without submitting it. | None |
| POST /api/py/v1/upload | A presigned form for a job's input file. | API key or signed-in session |
| POST /api/py/v1/jobs | Submit a simulation job. | Optional: API key |
| GET /api/py/v1/jobs/{job_id} | A job's status, progress and, once complete, its result link. | The identity that submitted it |
| GET /api/py/v1/jobs | The caller's recent jobs, from every key of the account. | API key or signed-in session |
Submit and poll
Read the contract, POST the job with its params (and inputFileKeys for an uploaded file), and get 202 with a jobId. With a key, a submission counts as one call against the allowance.
Poll GET /api/py/v1/jobs/{jobId} with the same identity that submitted it. The status carries progress, stage, finishedAt, elapsedSeconds, errorKind and, once complete, a presigned resultUrl. GET /api/py/v1/jobs lists your recent jobs, including ones submitted with any key the account holds. The Python library polls the way the web app does: job.wait() checks at once, then every 2 s, 5 s and 15 s as the job runs on.
Job types
13 job types. The parameter list of each is at /api/py/v1/jobs/types/{jobType}.
| jobType | Simulator | Uploads |
|---|---|---|
antenna_sim14 parameters | Wire Antenna Simulator (NEC-2) | None |
emi_radiated11 parameters | EMI Radiated Emissions Estimator | None |
eye_diagram11 parameters | Eye Diagram from S-Parameters | Required, up to 1 × .s2p / .s4p |
fdtd_sparam17 parameters | FDTD Transmission Line Simulator | None |
filter_monte_carlo15 parameters | RF Filter Monte Carlo Analysis | None |
impedance_match14 parameters | Broadband Impedance Matching Synthesizer | Optional, up to 2 × .s2p / .s1p |
magnetics_optimizer14 parameters | Magnetics & Transformer Design Optimizer | None |
pdn_impedance16 parameters | PDN Impedance Analyzer & Decoupling Capacitor Optimizer | None |
radar_detection15 parameters | Radar Detection Performance Monte Carlo | None |
rf_cascade8 parameters | RF Cascade Budget Analyzer | Optional, up to 12 × .s2p |
sat_link_budget14 parameters | Satellite & Terrestrial Link Budget | None |
smps_control_loop36 parameters | SMPS Control Loop Stability Analyzer | None |
sparam_pipeline3 parameters | S-Parameter Analysis Pipeline | Required, up to 4 × .s1p / .s2p / .s3p / .s4p |
What a job would cost
POST /api/py/v1/jobs/estimate takes the body a submission would send and answers with the lane it would run on, the expected wall time, whether it fits the lane's budget, and, on the paid lane, the credits it would record. It is never charged, needs no key, and runs the same checks as a submission, so it refuses exactly when a submission would. Credits are shown and recorded but not charged yet.
When a request is refused
A submission is checked against its contract before anything is queued or charged. A request outside it is a 400 naming every offending parameter, not the first one reached; nothing is queued and no allowance is spent. Unknown parameter keys are refused rather than ignored.
Error kinds
Every failure carries errorKind beside its message, on a refused submission and on a job that failed after it was accepted. This is a closed set; branch on it rather than on the wording of the message, which is written for people and may change.
| errorKind | Meaning |
|---|---|
| invalid_request | A parameter is missing, of the wrong type, out of range, not one of the declared options, or not a parameter of this job type. The 400 body lists every offending parameter. |
| too_large | The request is within the contract but beyond what this tier's lane can run. Reduce the size of the problem. |
| not_available | The request asks for a mode or a feature this tier does not carry. The message names what the tier does include. |
| rate_limited | A concurrent-job limit or a monthly allowance is spent. Carries Retry-After, and resetAt when the allowance is monthly. |
| timeout | The job exceeded its type's time ceiling. Nothing is charged for it. |
| interrupted | The run stopped before it finished — a worker was replaced or a task was stopped. Nothing is charged for it. |
| result_expired | The job completed, but its result is no longer stored. The status still reads completed and carries no resultUrl. |
| transient | The service could not accept or check the request just now. Nothing was queued or charged; try again. |
| fault | The service failed while computing. The message says which step; nothing is charged for it. |
Limits, duplicates and lifetimes
Concurrency
429 with Retry-After and a body carrying pending and limit.Duplicate submissions
Idempotency-Bypass: true to run it again anyway.Uploads
POST /api/py/v1/upload needs a key or a signed-in session and returns a presigned POST form valid for 5 minutes. At most 10 MB a file, enforced by the form itself. Accepted: .s1p .s2p .s3p .s4p .s6p .s8p .snp .csv .txt. The uploaded object is kept for 24 hours, so submit the job that uses it within the day. 20 forms a minute per address.Results
resultExpiresAt is when the result itself goes: 30 days on the free plan, kept indefinitely on Pro and API. resultUrlExpiresIn is how long the presigned resultUrl lasts: 15 minutes. Poll again for a fresh link; do not cache the URL. Once the result is gone the status still reads completed, with kind result_expired and no URL.What changed for callers who omit a parameter
Each job type has one definition of its parameters, and the handlers' own fallbacks are gone. If you send every field, nothing changed. If you omit one of these, the value used is different from before, and so is the answer.
| jobType | Parameter | Was | Now |
|---|---|---|---|
rf_cascade | nfSpec_db | 10 dB | 6 dB |
rf_cascade | inputPower_dbm | −60 dBm | −70 dBm |
rf_cascade | bandwidth_hz | 1 MHz | 10 MHz |
rf_cascade | stages | "[]" | required — no default |
smps_control_loop | toleranceDistribution | uniform | gaussian |
filter_monte_carlo | freqCutoff | 1 MHz | 1 GHz |
impedance_match | freqStart | 1 MHz | 800 MHz |
impedance_match | freqStop | 100 MHz | 1.2 GHz |
antenna_sim | freq (instant solve) | 145 MHz | 146 MHz |
pdn_impedance | portX_mm | board centre (boardWidth_mm / 2) | one-third point (boardWidth_mm / 3) |
pdn_impedance | portY_mm | board centre (boardLength_mm / 2) | one-third point (boardLength_mm / 3) |
Unknown parameter keys were previously dropped and answered under a default. They are now refused, and the refusal lists the keys the job type accepts.
For the job types that sample (filter_monte_carlo and the other optimisers) the random seed is derived from the body you submit, so the same design sent with different keys draws a different sample. Omitting a parameter and sending it at its default are the same request to the solver but not the same body, which is why a run from the web form and a run from this API can differ within sampling error. Send randomSeed to pin a run exactly.
Changes in the September 2026 release
Behaviour that changed for an existing integration. If you send every parameter and check errorKind rather than message text, the only differences you should see are these. Later changes, and the date each was announced, are on the API changelog.
What changed
- Unknown parameter keys and out-of-range values are refused at submit with a 400 naming the offending parameter, rather than being dropped or clamped and answered anyway.
- Eleven parameter defaults changed for a caller who omits the field; see the table above.
- A spent monthly allowance is now HTTP 402 (errorKind rate_limited) with Retry-After and resetAt, never a 401 and never a plain 429. This covers both the API-key month and the FDTD solve-mode quota.
- An upload now needs a signed-in session or an API key; an anonymous request gets a 401 before anything is stored. The anonymous free lane loses the two file-input tools (eye_diagram, sparam_pipeline) entirely, since neither runs without an uploaded file.
- A job submitted with an API key now belongs to the key's owner account: it is authorised by owner, not just by key id or submitting IP, and it appears in the owner's dashboard job listing.
- A completed result now carries warnings and provenance (method, version, seed and the normalised inputs actually used) alongside the computed values.
- Every failure — a refused submission and a job that failed after being accepted — now carries errorKind. See the closed set above.
- A job whose worker dies mid-run — replaced, or its task stopped — is now failed with kind interrupted rather than left stuck, and any charge for it is released.
- A result is kept for exactly as long as its record says: see resultExpiresAt in the Results card above.
- The impedance synthesiser's Auto topology now compares all five topologies and returns the best worst-case return loss — it always built an L network before, in both quick mode and the advanced default.
- The impedance synthesiser now honours maxQ and componentSeries; both were accepted and silently ignored before.
- The E-series standard-value snap now rounds a mantissa above about 9.55 up to the next decade's first value (9.9 nF → 10 nF) instead of down. This can change one part value in an impedance-match design or a filter Monte Carlo run for the same input.
- SPICE netlists exported from the impedance page now carry the standard (snapped) component values, not the ideal ones, with a header line naming the series.
- Power-inductor and coupled-inductor designs are now sized from the inductance and peak current you give them, rather than derived from other inputs; flyback and forward transformers are unchanged. A request whose stated peak current is inconsistent with its stated inductance's ripple comes back with a ripple_exceeds_peak warning.
- Deploy note: the API validator deployed ahead of the worker during this rollout, so a job queued in that window whose body carried a misspelled key — previously accepted silently under a default — was refused at submit instead of run to completion.