Talk to your building.

Normalize Honeywell, Johnson Controls, Schneider, Siemens BMS telemetry. Monitor HVAC, energy, occupancy in plain English.

Any OEMΒ·Any machineΒ·Natural languageΒ·Verified on-chain

Watch the demo Get your API key

Self-serve signup

By continuing, you agree to the Terms of Service and Privacy Policy.

"Connect the HVAC unit in Building A"
System MINT-bld001 provisioned on Solana
"Alert me when zone 3 CO2 exceeds 1000 PPM"
Automation armed β€” monitoring building.zone_3_co2_ppm
"Show me energy consumption this week"
Building A: 4,287 kWh Β· -8% vs last week
"New reading: zone_3_co2_ppm at 1142"
Alert fired β†’ Slack #facilities (186ms)

Three steps. No code.

01Connect

Identify any machine by OEM, model, and serial. Or connect any business system via webhook. The agent works with machines and software.

02Talk

Send telemetry in any format or trigger evaluations from any source. Set up automations in one sentence. "Alert when coolant exceeds 30" or "notify purchasing when inventory drops below 50."

03Act

Triggers fire to any system. Slack, ERP, CMMS, MES, email. Everything logged, auditable, and settled on Solana.

Claude Code for your operations.

The same AI that writes code from natural language can run your business operations. Update your ERP. Create work orders. Trigger purchase orders. Send shift reports. All from one sentence.

Machines

Connect any CNC, robot, or industrial equipment. The agent normalizes telemetry from any OEM, monitors health continuously, and takes action when conditions change. Every reading verified on-chain.

"Connect the Haas VF-2SS on Line 4"
"Alert when spindle load exceeds 85%"
"How's this machine trending?"

Operations

Connect any business system with a webhook. The agent triggers actions across ERP, CMMS, MES, quality, scheduling, email, and any HTTP endpoint. No integration code. No middleware. One sentence.

"When inventory drops below 50, notify purchasing"
"Every Friday at 5pm, send the production summary"
"Create a work order for coolant system maintenance"

Same agent. Same billing. Same audit trail. Machines and software, unified through natural language.

Works with everything you already have.

OEMs Honeywell Johnson Controls Schneider Siemens Tridium
Systems SlackSAP EpicorOracle FiixUpKeep MaintainXPlex IgnitionAny webhook

Works with Claude Desktop, Cursor, GPT, or any MCP-compatible client. Complements AWS IoT, Azure IoT, Siemens MindSphere, PTC ThingWorx.

Pay for what you use.

Starter recommended
Normalize1Β’/call
Trigger5Β’/fire
Settle2Β’/batch
History1Β’/query

No minimums. No contracts. Pay as you go.

Get free API key

50 free normalize calls to start. No card required.

Growth 100K+/mo Β· 30% off
Normalize0.7Β’/call
Trigger3.5Β’/fire
Settle1.4Β’/batch
History0.7Β’/query

30% volume discount. Monthly invoice.

Card required. Discounted pricing from your first call.

Enterprise 1M+/mo Β· 60% off
Normalize0.4Β’/call
Trigger2Β’/fire
Settle1Β’/batch
History0.4Β’/query

Custom SLA. Dedicated MCP endpoint. Annual contract.

Contact us

Identity: free. Automation setup: free. Trigger evaluation: free. Feedback: free.
No subscriptions. No minimums. No contracts.

One API. Every deployment.

Add FoundryNet to your integration toolkit. Every machine you connect gets cross-manufacturer normalization, natural-language automations, and on-chain verification. Your customers get smarter machines. You get recurring revenue from every API call.

Become an integrator partner

Integrator revenue share program coming soon. Earn on every machine you connect.

Connect in 30 seconds.

Drop this into your Claude Desktop config:

{
  "mcpServers": {
    "foundrynet": {
      "command": "npx",
      "args": ["mcp-remote",
        "https://foundrynet-mcp-production.up.railway.app/sse"]
    }
  }
}

11 tools. SSE transport. Works with any MCP client.


API Reference

All /v1/* requests need Authorization: Bearer fnet_… and (where applicable) Content-Type: application/json. Base URL: https://forge.foundrynet.io.

Quick start

  1. Get your API key: self-serve via POST /v1/keys/checkout β†’ Stripe Checkout β†’ POST /v1/keys/activate (or use the form at the top of this page)
  2. Identify a machine: POST /v1/identify
  3. Send data: POST /v1/normalize
  4. Connect a tool: POST /v1/tools
  5. Set up automation: POST /v1/triggers/natural
  6. Query history: GET /v1/history/{mint_id}
  7. Verify on-chain: POST /v1/settle

Endpoints

POST /v1/identify

Provision or look up a persistent on-chain identity (mint_id) for one machine. Idempotent on (oem, model, serial).

{
  "oem":    "fanuc",
  "model":  "M-20iA",
  "serial": "R30iB-12345",
  "site":   "Line 3"
}
{
  "mint_id":     "MINT-4de03b",
  "internal_id": "fanuc:m-20ia:r30ib-12345",
  "created":     true,
  "machine":     { "wallet_address": "EfXdpMDk…", "status": "active" },
  "first_seen":  "2026-05-04T01:00:00Z"
}
POST /v1/normalize

Translate raw OEM telemetry to canonical FCS data. Auto-provisions identity from oem/model/serial when no machine_id is given. Returns triggers_fired[] when any active trigger matches. Optional idempotency_key dedups retries within 24h. Optional observed_at (ISO 8601 controller clock) is stored alongside the server ingested_at.

{
  "data":   { "Spindle_Speed": 2200, "spindle_load": 92 },
  "oem":    "fanuc",
  "model":  "M-20iA",
  "serial": "R30iB-12345",
  "observed_at":     "2026-05-05T09:30:15Z",
  "idempotency_key": "optional-caller-supplied-key"
}
{
  "normalized":      { "spindle_speed_rpm": 2200, "spindle_load_pct": 92 },
  "field_mappings":  { "spindle_load": { "mapping_id": "6c34…", "canonical": "spindle_load_pct", "confidence": 0.93 } },
  "fields_total":    2, "fields_renamed":  2, "fields_identity": 0, "fields_unknown":  0,
  "coverage_pct":    100,
  "machine_id":      "MINT-4de03b",
  "history_id":      "c419…",
  "triggers_fired":  [{ "trigger_id": "7f0c…", "trigger_name": "high spindle load", "actual_value": 92 }]
}
POST /v1/tools

Register a webhook endpoint as a tool. Triggers reference these by tool_id. auth_secret returned ONCE on create; never read back via GET.

{
  "name": "slack-maintenance",
  "url":  "https://hooks.slack.com/services/T…/B…/xxx",
  "method": "POST",
  "payload_template": { "text": "Alert: {{oem}} {{model}} β€” {{field}} at {{value}}" },
  "auth_type": "none"
}
{ "id": "add2…", "name": "slack-maintenance", "auth_type": "none", "enabled": true }
POST /v1/triggers/natural

Parse a natural-language instruction into a structured trigger. NEVER auto-activates; returns parsed_trigger for review and explicit POST to /v1/triggers.

{ "machine_id": "MINT-4de03b", "instruction": "Alert maintenance Slack when spindle load exceeds 90." }
{
  "parsed_trigger": {
    "machine_id": "MINT-4de03b",
    "name": "Spindle Load Alert",
    "condition": { "field": "spindle_load_pct", "op": ">", "value": 90 },
    "actions":   [{ "tool_id": "add2…" }]
  },
  "confirmation_required": true
}
GET /v1/history/{mint_id}

Per-machine canonical history. Query params: from, to (ISO-8601), fields (csv), limit (≀1000), summary (bool).

GET /v1/history/MINT-4de03b?limit=5&summary=true
{
  "mint_id":  "MINT-4de03b",
  "machine":  { "oem": "fanuc", "model": "M-20iA", "site": "Line 3" },
  "row_count": 2,
  "avg_coverage": 100,
  "fields_covered": ["spindle_load_pct", "spindle_speed_rpm", "sensor_readings.coolant_temp"]
}
POST /v1/settle

Anchor data on Solana mainnet via the MINT relay. Add ?batch=true with body {"mint_id": "…"} to Merkle-root all unsettled events for that machine into one transaction.

POST /v1/settle?batch=true
{ "mint_id": "MINT-4de03b" }
{
  "mint_id":      "MINT-4de03b",
  "merkle_root":  "413d5ec…",
  "event_count":  4,
  "tx_signature": "2yiyp…",
  "verify_url":   "https://solscan.io/tx/2yiyp…"
}

MCP server

SSE endpoint: https://foundrynet-mcp-production.up.railway.app/sse

11 tools

Reliability + provenance

Soft delete

DELETE /v1/triggers/{id} defaults to soft delete β€” sets deleted_at, hides from list/eval, restorable for 30 days via PATCH /v1/triggers/{id}/restore. Add ?permanent=true for irrecoverable hard delete.

Idempotency

/v1/normalize accepts an optional idempotency_key. If absent, server synthesizes sha256(mint_id + canonical(data))[:32]. Repeats within 24h return the original response with deduplicated: true and skip trigger evaluation.

Coverage metric

Every /v1/normalize response carries three counters: fields_renamed (source != canonical), fields_identity (source == canonical), fields_unknown (no mapping). coverage_pct = (renamed + identity) / total.

Provenance timestamps

observed_at (ISO 8601 from the controller clock) is optional on /v1/normalize. Stored alongside ingested_at (server). When the difference exceeds 60s, response includes clock_skew_warning. Sustained-condition windows reference observed_at when present.

Structured errors

{
  "error":  true,
  "status": 422,
  "field":  "body.oem",
  "reason": "Field required",
  "received_value": {},
  "suggestion":     "e.g. 'fanuc'",
  "additional_errors": [ { "field": "body.model", "reason": "Field required" } ]
}

Pricing

Metered billing via Stripe. Counts roll up to your subscription's current billing period and settle on Stripe's normal cycle. Query GET /v1/usage for live counts and an estimated bill.

Get an API key via the self-serve flow: POST /v1/keys/checkout with {email} returns a Stripe Checkout URL; after the user adds a card, POST /v1/keys/activate with {session_id} returns the fnet_… key (shown once). Admin / CI keys can be minted with an X-Admin-Token header bypass on POST /v1/keys.