Skip to content

Refresh the bundled OpenAPI spec

The bundled OpenAPI spec at src/mcsinglewire/data/openapi.json is a frozen snapshot of https://openapi.icmobile.singlewire.com/api/openapi.json. Refreshing it changes what’s reachable via api_call — every refresh is a re-audit trigger (Safety model § 10).

  1. Pull the latest spec

    Refresh from upstream
    make refresh-spec

    This downloads the upstream JSON and writes it to src/mcsinglewire/data/openapi.json. Use the Makefile target rather than curl directly — the target is the canonical entry point and keeps diffs reviewable.

  2. Review the diff

    Inspect what changed
    git diff src/mcsinglewire/data/openapi.json

    Things to look for:

    • New operationIds — especially new GETs. Some “GETs” have side effects in disguise (Singlewire’s spec sometimes describes simulation, dispatch, or recipient interpolation in the description of a GET). Anything ambiguous is a denylist candidate.
    • Renamed or removed operationIds. A failing build will tell you later, but it’s cheaper to notice now.
    • Changed scope requirements. The spec annotates each operation with the OAuth scopes required. A previously-readable endpoint that now requires :write or :manage will start returning 401 — that’s correct behaviour for this server, but worth knowing.
    • New tags / categories. No action required; they show up in list_tags() automatically.
  3. Scan new GETs against the denylist

    The denylist lives in src/mcsinglewire/server.py:

    src/mcsinglewire/server.py
    _GET_DENYLIST: dict[str, str] = {
    "getScenario": (
    "Singlewire spec describes a 'simulate answers' mode for this GET ..."
    ),
    }

    For every newly-added GET, read its description in the spec carefully. If the wording contains any of the following, the operation belongs on the denylist:

    • “simulate”, “dispatch”, “send”, “trigger”, “execute”
    • “would be sent”, “would be delivered”
    • Anything mentioning recipient interpolation as a side effect of reading

    When in doubt, denylist it and ask Singlewire in writing. A denylisted operation can be re-enabled with one line of code; a recipient blast that shouldn’t have happened cannot.

    See Add an operation to the denylist for the exact mechanics.

  4. Run the test suite

    Lint + tests
    make check

    tests/test_spec.py enforces that every operationId is unique — duplicate IDs fail the build before they reach production. tests/test_server.py covers the validation surface, so a renamed parameter surfaces here too.

  5. Commit

    Commit the snapshot
    git add src/mcsinglewire/data/openapi.json
    git commit -m "Refresh ICMobile OpenAPI spec ($(date +%Y-%m-%d))"

    If the diff included denylist changes, group them in the same commit and reference the specific operationIds in the message — it makes the audit trail much easier to read later.

There’s no automated trigger. Reasonable cadences:

  • Quarterly, as routine maintenance.
  • On demand, when Singlewire announces an API addition you want to use.
  • Before any audit, so the bundled spec matches the live API at audit time.

The refresh is a re-audit trigger — see Safety model § 10. After a refresh, walk through the safety model before resuming use.