Skip to content
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

Job endpoints
EndpointWhat it doesCredential
GET /api/py/v1/jobs/typesEvery 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/estimateWhat a job would cost and how long it would run, without submitting it.None
POST /api/py/v1/uploadA presigned form for a job's input file.API key or signed-in session
POST /api/py/v1/jobsSubmit 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/jobsThe 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}.

Job types
jobTypeSimulatorUploads
antenna_sim14 parametersWire Antenna Simulator (NEC-2)None
emi_radiated11 parametersEMI Radiated Emissions EstimatorNone
eye_diagram11 parametersEye Diagram from S-ParametersRequired, up to 1 × .s2p / .s4p
fdtd_sparam17 parametersFDTD Transmission Line SimulatorNone
filter_monte_carlo15 parametersRF Filter Monte Carlo AnalysisNone
impedance_match14 parametersBroadband Impedance Matching SynthesizerOptional, up to 2 × .s2p / .s1p
magnetics_optimizer14 parametersMagnetics & Transformer Design OptimizerNone
pdn_impedance16 parametersPDN Impedance Analyzer & Decoupling Capacitor OptimizerNone
radar_detection15 parametersRadar Detection Performance Monte CarloNone
rf_cascade8 parametersRF Cascade Budget AnalyzerOptional, up to 12 × .s2p
smps_control_loop36 parametersSMPS Control Loop Stability AnalyzerNone
sparam_pipeline3 parametersS-Parameter Analysis PipelineRequired, 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.

Error kinds
errorKindMeaning
invalid_requestA 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_largeThe request is within the contract but beyond what this tier's lane can run. Reduce the size of the problem.
not_availableThe request asks for a mode or a feature this tier does not carry. The message names what the tier does include.
rate_limitedA concurrent-job limit or a monthly allowance is spent. Carries Retry-After, and resetAt when the allowance is monthly.
timeoutThe job exceeded its type's time ceiling. Nothing is charged for it.
interruptedThe run stopped before it finished — a worker was replaced or a task was stopped. Nothing is charged for it.
result_expiredThe job completed, but its result is no longer stored. The status still reads completed and carries no resultUrl.
transientThe service could not accept or check the request just now. Nothing was queued or charged; try again.
faultThe service failed while computing. The message says which step; nothing is charged for it.

Limits, duplicates and lifetimes

Concurrency

3 jobs queued or running at once, per caller. Over it, the API returns 429 with Retry-After and a body carrying pending and limit.

Duplicate submissions

An identical request from the same caller within 60 s returns the existing job, with its real status, so a job that already failed comes back as failed with its reason. Send 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

Two different clocks. 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.

Changed defaults
jobTypeParameterWasNow
rf_cascadenfSpec_db10 dB6 dB
rf_cascadeinputPower_dbm−60 dBm−70 dBm
rf_cascadebandwidth_hz1 MHz10 MHz
rf_cascadestages"[]"required — no default
smps_control_looptoleranceDistributionuniformgaussian
filter_monte_carlofreqCutoff1 MHz1 GHz
impedance_matchfreqStart1 MHz800 MHz
impedance_matchfreqStop100 MHz1.2 GHz
antenna_simfreq (instant solve)145 MHz146 MHz
pdn_impedanceportX_mmboard centre (boardWidth_mm / 2)one-third point (boardWidth_mm / 3)
pdn_impedanceportY_mmboard 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.