Pre-alpha, in active development

Sniff out metrics from any API, without ever blowing your rate limits.

Tapyr collects data from the REST APIs of your cloud-managed network gear, normalizes it, and exports clean Prometheus or OTLP metrics. One declarative definition per API, no code to write.

See how it works Read the design soon

From vendor APIs to your metrics stack

VisualCode
Cloud APIs for SD-WAN, SD-LAN, Wi-Fi, 4G/5G routers and any other SD-* platform feed Tapyr, which polls, normalizes and paces calls, then exports Prometheus and OTLP metrics, with room for other formats. SD-WANbranch appliancesSD-LANcloud-managed switchesWi-Fiaccess point controllers4G / 5G routerscellular gatewaysAny SD-* APIyour definition nextPrometheusexposition, remote writeOTLPany OTLP backendOther formats?open to proposals tapyrpoll, paginate, retrynormalize labels, unitsspend quota on budget
  • SD-WAN
  • SD-LAN
  • Wi-Fi
  • 4G / 5G routers
  • Any SD-* API
tapyrpoll, paginate, retrynormalize labels, unitsspend quota on budget
  • Prometheus
  • OTLP
  • Other formats?

What the API returns

vendor REST API
GET /v1/devices?page=1
{
  "data": [{
    "id": "dev-0142",
    "name": "branch-12-ap",
    "status": "online",
    "signal": { "rssi": -61 }
  }, ...],
  "meta": { "next": 2 }
}

Provider definition

YAML + CEL
metrics:
  - name: device_up
    value: item.status == "online"
  - name: signal_rssi_dbm
    value: item.signal.rssi
labels:
  device: item.name

What you get

# every page, every device
tapyr_device_up{
  provider="wifi_cloud",
  device="branch-12-ap"} 1
tapyr_signal_rssi_dbm{
  provider="wifi_cloud",
  device="branch-12-ap"} -61

Illustration. Field and metric names are examples, the definition syntax is not final.

And it never runs your quota dry

Cloud APIs ration calls in many ways, often several at once. When one of those budgets runs dry, every device you monitor goes flat until the window resets, and the cause hides in a response header.

  • per second
  • per minute
  • daily
  • weekly
  • monthly
  • per organization
  • concurrency

Tapyr declares those limits once per provider, plans every call against them, keeps a reserve for retries, and exports its own quota metrics so you see trouble coming.

window opensquota hitreset HTTP 429quota exhaustedno data until reset
What a dashboard shows when an API quota runs out before its window resets. Illustration.

How it works

You describe an API once: its endpoints, how to page through them, how its JSON becomes metrics, and every limit it enforces. The budget engine schedules each call against those limits, the collector fetches, the normalizer maps, the exporters deliver.

A provider definition feeds the budget engine, which schedules the collector. The collector calls the vendor API or the built-in simulator, the normalizer maps the answers to metrics, and the exporters deliver them as Prometheus or OTLP. tapyr plan projects the cost of a configuration before deploy, and Tapyr exports its own metrics and serves a read-only web UI. DefinitionYAML + CEL per APIBudget engineplans every callCollectorpoll, paginate, retryNormalizernames, labels, unitsExportersPrometheus, OTLPVendor APIor built-in simulatortapyr planprojects calls per quota, before you deploySelf-metrics and web UIcalls, 429s, quota left, job freshness
  1. DefinitionYAML + CEL per API
  2. Budget engineplans every call against the limits
  3. Collectorcalls the vendor API, or the built-in simulator
  4. Normalizernames, labels, units
  5. ExportersPrometheus, OTLP
  • tapyr planprojects calls per quota, before you deploy
  • Self-metrics and web UIcalls, 429s, quota left, job freshness

Limits are part of the config

Declare what the vendor enforces, once per provider. Then ask Tapyr what your jobs will cost before anything touches the real API.

Declare limits

A per-organization rate, plus a daily quota that resyncs from the API's own headers.

limits:
  - name: org-rate
    kind: rate
    rate: 10/s
    scope: { by: [account, "var:organizationId"] }
  - name: daily
    kind: quota
    max: auto
    initialMax: 5000
    window: { period: day, resetAt: "00:00", timezone: UTC }
    sync:
      limitHeader: X-RateLimit-Limit-day
      remainingHeader: X-RateLimit-Remaining-day

Plan before you deploy

tapyr plan projects what each quota window will spend, and stretches low-priority jobs to fit.

$ tapyr planQUOTA SCOPE       BUDGET/DAY  PROJECTED  RESERVE  STATUSwifi-cloud/daily  4500        4212       450      ok (93.6%)  job wifi-aps      desired 5m   effective 5m                    288 runs x 3 pages  = 864  job wifi-clients  desired 5m   effective 15m                    96 runs x 30 pages  = 2880                    (stretched x3, priority low)

What's coming in v0.1

Everything below is in development. Nothing is released yet.

Many APIs in, standard metrics out

Poll one or several vendor APIs, follow pagination, normalize names, labels and units, then export clean metrics.

Declarative

YAML plus CEL. A new API needs a definition, not Go code.

Rate limits, first class

Any window, any scope, retries included. Budgets resync from the API's quota headers.

tapyr plan

Know what a config will spend on each quota before you deploy it.

Built-in simulator

Every provider ships with one that enforces the real limits. No vendor account needed.

Monitors itself

Calls, retries, 429s, quota left, projected exhaustion and job freshness, as metrics. Plus a read-only web UI in the binary.

Open source, self‑hosted, built in Europe

Tapyr won't make data from US clouds sovereign. It just doesn't add another middleman between your network and your dashboards.

  • Open source

    Apache-2.0. Read it, fork it, write your own providers.

  • Self-hosted

    One static binary on your infrastructure. No account, no SaaS.

  • No middleman

    No telemetry, no third party. Your metrics stay with you.