Work in progressThese docs are still being written and are currently mostly AI-generated. Some details may be inaccurate or incomplete.

Push from your own servers

Raise on-call pages and report your own cost data over the HTTP API, from code running anywhere.

Most of what Infrawrench knows, it went and fetched. Two things it can’t: an alert about something only your code can see, and spend that arrives as an invoice rather than a billing API.

Both have an endpoint that pushes into Infrawrench, so a health check, a deploy script, or a cron on a box can hand over what it knows and let the org’s existing configuration decide what happens next.

You want toEndpointPermission
Wake somebody upPOST /api/org/{orgId}/pagespages:write
Clear a page’s cooldownDELETE /api/org/{orgId}/pagespages:write
Report spend from your systemsPOST /api/org/{orgId}/costs/rowscosts:write

Both authenticate with an API key (Authorization: Bearer iwk_…) scoped to just that permission — or with a signed-in session, which is what makes them testable from the browser. Neither is in a system role by default: mint a key with the scope, or add it to a custom role.

Paging

POST /pages raises the same alert a workflow raises with infra.page(...), and it reaches the same people: SMS (and optionally a voice call) through your org’s Twilio credentials, mobile push, and any Slack or Microsoft Teams channel opted into pages. Recipients configure themselves under Settings → Notifications; the caller doesn’t hold a single transport credential.

curl -X POST https://app.infrawrench.com/api/org/$ORG/pages \
  -H "Authorization: Bearer $INFRAWRENCH_API_KEY" \
  -H "content-type: application/json" \
  -d '{
        "source": "checkout-api",
        "title": "Checkout 5xx",
        "message": "5xx rate above 2% for 5 minutes",
        "key": "5xx-rate"
      }'

source is your name for the system doing the paging. It becomes the notification’s sender, and it scopes the throttle — two services paging under the key disk-full never silence each other.

Repeat pages are suppressed, not rejected

A monitor re-finds the same problem on every tick. Calling this endpoint every minute would be 1,440 messages a day about one broken thing, so every page carries a key, and a page under a key that already fired is held quiet until its cooldown elapses — one hour by default.

That means you should call it unconditionally and read the response rather than tracking state yourself:

{
  "delivered": false,
  "suppressed": true,
  "sms": 0,
  "push": 0,
  "slack": 0,
  "msTeams": 0,
  "retryAt": "2026-07-27T15:30:00.000Z"
}

A suppressed page is a 200. So is a page that reached nobody — but that one does not start a cooldown, so the next call tries again instead of going quiet after a failed delivery.

FieldDefaultWhat it does
sourcerequiredNames the system paging. Letters, digits, ., _, -; up to 64 characters.
messagerequiredThe alert text. Becomes the SMS body and the notification body.
titlesourceHeadline of the notification.
keydefaultThrottle bucket. Use a per-object key (a host, a cluster) to alert per object.
cooldownMinutes60How long a key stays quiet after firing. 0 sends every time.
voicefalseAlso place a voice call to recipients who opted into voice. Reserve it for waking people up.

When the condition recovers, clear the key so the next occurrence pages immediately instead of waiting out a stale timer:

curl -X DELETE "https://app.infrawrench.com/api/org/$ORG/pages?source=checkout-api&key=5xx-rate" \
  -H "Authorization: Bearer $INFRAWRENCH_API_KEY"

Settings → Notifications with the Pages trigger enabled on a Slack channel and a mobile device, so a reader can see where a pushed page lands

Cost rows

POST /costs/rows reports spend Infrawrench has no plugin for — a parsed SaaS invoice, an internal chargeback, a colo bill. The rows land in the same store the provider collectors write to, so they appear in cost graphs, dimension filters, and budgets with no special-casing.

curl -X POST https://app.infrawrench.com/api/org/$ORG/costs/rows \
  -H "Authorization: Bearer $INFRAWRENCH_API_KEY" \
  -H "content-type: application/json" \
  -d '{
        "source": "snowflake-invoices",
        "rows": [
          { "date": "2026-07-26", "currency": "USD", "amount": 412.55,
            "service": "Snowflake Compute", "tags": { "team": "data" } },
          { "date": "2026-07-26", "currency": "USD", "amount": 38.10,
            "service": "Snowflake Storage" }
        ]
      }'

Each row is one day of spend for one combination of dimensions. date, currency, and amount are required; service, region, resourceId, tags, usageAmount, and usageUnit are the dimensions you can then group and filter by. amount may be negative for a credit.

Rows show up under the provider External and, unless you attribute them to one of your accounts with accountId, in the account dimension as “<source> (external)”.

Pushing the same day twice restates it

Writes are keyed by (source, day, service, region, resourceId, tags, currency). Re-pushing a day replaces those rows rather than adding to them, so a nightly job can safely re-push a trailing window to absorb late-arriving invoice lines — the same restatement behaviour the provider collectors get.

Rows pushed under a source can never overwrite rows a collector wrote, even when you attribute them to a real account, and two sources can never overwrite each other.

The whole batch is validated before anything is stored, so a 400 means nothing was written and the message names the offending row:

{ "error": "costs/rows: row 3 has an invalid currency \"dollars\" (expected a 3-letter ISO code)." }

Limits: 5,000 rows per call, 32 tags per row, 256 characters per field. Tag keys beginning infrawrench: are reserved and rejected — that namespace is what keeps sources from colliding.

From the CLI

The infrawrench CLI wraps both, which is often the shortest path on a server that already has it installed:

# Page, honouring the same cooldown as the API
infrawrench page "backup did not complete" --source backups --key nightly

# Recovered — re-arm the key
infrawrench page clear --source backups --key nightly

# Push cost rows from a file, or from a pipeline
infrawrench costs push --source colo --file rows.json
parse-invoice --json | infrawrench costs push --source colo

Both accept --json for scripting, and both use the CLI’s existing sign-in rather than a separate key.

Doing this from a workflow instead

If the thing you’re checking is reachable from Infrawrench — a cloud API, a database, an SSH host — a workflow is usually less work than a server: it has infra.page(...) and infra.costs.write(...) built in, runs on a schedule you set in the UI, and needs no key to manage. These endpoints are for code that runs where Infrawrench doesn’t.

Supported providers

44 providers · 340+ resource types across cloud, infrastructure, databases, and more.