Skip to content
RFrftools.io

API Changelog

Every change to the public API that a caller could notice, newest first. Each entry is dated the day it was announced here; a change that breaks existing callers is announced no later than the release that makes it, and is marked Breaking. 2 of the 8 entries below are breaking.

  1. Added

    A target-solve call: search a calculator input for a target output

    • POST /api/py/v1/calculate/solve

    POST /api/py/v1/calculate/solve finds the value of one calculator input that brings one of its outputs to a target — the trace width that gives 50 Ω, the gap that gives a target differential impedance — and returns it with the forward result at exactly that value: values, warnings, errors and provenance, exactly what /calculate returns for those inputs. One metered call replaces the several forward calls a client would otherwise spend searching by hand.

    The search runs over the input's stated bounds, narrowed by an optional range; an input with no stated bound needs one. An optional grid rounds the returned value to its nearest multiple inside the range, alongside the unrounded solution. A target the search cannot reach still succeeds, with reached: false and the nearest value found, and is still charged. Refusals — an unknown calculator, an input or output name the calculator does not declare, a non-finite value, a missing range on an unbounded input — cost nothing, as for every other calculator route.

    The Python SDK's Client.solve() (rftools-io 0.4.0) and the MCP server's solve_calculation tool (2.2.0) expose the same call.

  2. ChangedBreaking

    A spent allowance on the calculator routes is 402, not 401

    • POST /api/py/v1/calculate
    • POST /api/py/v1/calculate/batch

    The calculator routes answered 401 "Invalid or quota-exceeded API key" both for a key that was not valid and for an allowance that was spent, so a script could not tell a bad key from a busy month. A spent allowance is now 402, as the jobs route already answered, with errorKind: "rate_limited", reason, limit, used, resetAt, upgradeUrl, overageUrl and a Retry-After header.

    401 now means only that the key is missing, malformed, unknown or revoked, and never mentions an allowance. A request with no key at all is 401 with a keyUrl where a free key can be had.

    A call is checked before it is counted: an unknown calculator (404) or an input that is not a finite number (400) costs nothing, and a calculation that fails is given back. In a batch, only the items that pass those checks are counted, and items whose calculation fails are given back. Branch on the status and errorKind, never on message text.

  3. ChangedBreaking

    The monthly allowance belongs to the account, shared by all its keys

    • POST /api/py/v1/calculate
    • POST /api/py/v1/calculate/batch
    • POST /api/py/v1/jobs

    Each key used to carry its own monthly allowance, so an account holding several keys could spend its allowance once per key. The allowance is now the account's: the calls of every key it holds, revoked ones included, count against one monthly figure, which resets at the start of each calendar month in UTC.

    An account with one key sees no difference. Calls are still attributed to the key that made them, and the dashboard and GET /api/py/v1/usage list them per key.

  4. Added

    A usage endpoint, and usage headers on every metered response

    • GET /api/py/v1/usage
    • X-Usage-Allowance
    • X-Usage-Used
    • X-Usage-Reset
    • X-Usage-Overage

    GET /api/py/v1/usage answers a key (X-API-Key or Authorization: Bearer rfc_…) or a signed-in session with the tier, the allowance, what is used and what is left, when it resets, the overage state and the calls attributed to each of the account's keys. Reading it is never counted.

    Every metered response carries X-Usage-Allowance, X-Usage-Used (including that call) and X-Usage-Reset, and X-Usage-Overage when overage was counted. Browsers can read them.

  5. Added

    Every result says how it was computed

    • POST /api/py/v1/calculate
    • POST /api/py/v1/calculate/batch
    • GET /api/py/v1/jobs/{jobId}

    Calculator results and each batch item carry a provenance object with nine members: method, version, formulaRef, assumptions, validRange, computedAt, inputs, seed and elapsedSeconds. Job results already carried provenance; it gains formulaRef, assumptions, validRange and computedAt rather than a second object, and its version is written worker@<revision> rather than the bare revision.

    An input outside the range a calculator is stated for is still computed: validRange names it and a warning is added. A result stored before this change keeps the members it had; treat an absent one as unknown.

  6. Added

    Programs can get a key through the device authorization grant

    • POST /api/py/v1/oauth/device/code
    • POST /api/py/v1/oauth/device/token
    • /device/

    A program with no browser in it can get a key without its user pasting one (OAuth 2.0 device authorization grant, RFC 8628). It asks /oauth/device/code for a code, shows its user the code and the address https://rftools.io/device/, and polls /oauth/device/token at the interval it was given. Once the user signs in and approves the code, the next poll returns an ordinary API key, once.

    The key is metered, listed and revocable like any other, and counts toward the account's key limit.

  7. Changed

    Refusals name the limit and the way past it

    • 429 responses
    • 402 from POST /api/py/v1/jobs
    • Authorization: Bearer rfc_…

    The per-minute 429 carries errorKind: "rate_limited", limit, windowSeconds and upgradeUrl beside detail, as every other refusal carries its errorKind. The jobs route's 402 for a spent allowance gains reason, limit, used, upgradeUrl and overageUrl, and the 402 for a spent fdtd_sparam solve-mode allowance carries reason: "solve_mode". Existing fields are unchanged.

    The calculator routes accept a key as Authorization: Bearer rfc_… as well as X-API-Key, as the jobs routes already did.

The full reference is the API documentation; the machine-readable description is the OpenAPI playground.