1<!doctype html> 2<html lang="en"> 3<head> 4<!-- Privacy-friendly analytics by Plausible -->
5<script async src="https://plausible.io/js/pa-QdPlluyoOE1jovqrkv-ed.js"></script>
vendor: 1 bytes, line 5
5
6<script> 7 window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}}; 8 plausible.init() 9</script>
9 10<meta charset="utf-8"> 11<meta name="viewport" content="width=device-width,initial-scale=1"> 12<meta name="google-site-verification" content="-Vk03AgXINQMCfsTNJqtCnbcdC92p3WtyyDDOCnckAU" /> 13<title>FoundryNet, Developer Docs & API Reference</title> 14<link rel="canonical" href="https://foundrynet.io/docs"> 15<meta name="description" content="FoundryNet Forge API reference: /v1/* endpoints, the 32-tool MCP server, quick start, reliability and security internals."> 16<meta property="og:title" content="FoundryNet, Developer Docs & API Reference"> 17<meta property="og:description" content="FoundryNet Forge API reference: /v1/* endpoints, the 32-tool MCP server, quick start, reliability and security internals."> 18<link rel="preconnect" href="https://fonts.googleapis.com"> 19<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 20<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> 21<style> 22 :root { 23 --bg: #08080d; 24 --bg-elev: #0c0f17; 25 --bg-term: #000000; 26 --bg-code: #050609; 27 --rule: #16202e; 28 --rule-soft: #0f1722; 29 --fg: #d8dfeb; 30 --fg-mid: #8d99ad; 31 --fg-dim: #5a6678; 32 --jade: #1a9058; 33 --jade-soft: #2dbb78; 34 --jade-glow: rgba(45, 187, 120, 0.35); 35 --amber: #f0a030; 36 --amber-glow: rgba(240, 160, 48, 0.35); 37 --max: 1020px; 38 } 39 * { box-sizing: border-box; } 40 html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); } 41 body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; 42 font-size: 15px; line-height: 1.7; font-weight: 400; 43 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } 44 h1, h2, h3 { font-family: 'JetBrains Mono', ui-monospace, monospace; 45 font-weight: 500; margin: 0; letter-spacing: -0.01em; } 46 h1 { font-size: clamp(36px, 5.5vw, 60px); line-height: 1.05; 47 color: var(--fg); font-weight: 600; letter-spacing: -0.025em; } 48 h2 { font-size: clamp(22px, 2.6vw, 30px); color: var(--fg); 49 margin-bottom: 18px; font-weight: 500; letter-spacing: -0.01em; } 50 h3 { font-size: 11px; color: var(--jade-soft); margin-bottom: 10px; 51 font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; } 52 p { margin: 0 0 14px; color: var(--fg); } 53 a { color: var(--jade-soft); text-decoration: none; 54 transition: color .15s ease; } 55 a:hover { color: var(--amber); } 56 ul, ol { color: var(--fg-mid); padding-left: 20px; line-height: 1.85; } 57 li { margin: 4px 0; } 58 code { font-family: 'JetBrains Mono', monospace; font-size: 0.92em; 59 color: var(--amber); background: transparent; } 60 61 section { padding: 90px 28px; max-width: var(--max); margin: 0 auto; } 62 section.first { padding-top: 130px; } 63 64 .label { font-family: 'JetBrains Mono', monospace; font-size: 11px; 65 color: var(--fg-dim); font-weight: 400; letter-spacing: 0.22em; 66 text-transform: uppercase; } 67 68 /* HERO ---------------------------------------------------------- */ 69 .hero p.sub { font-size: 22px; color: var(--fg-mid); margin: 22px 0 32px; 70 max-width: 640px; font-weight: 300; line-height: 1.5; } 71 .proof { color: var(--jade-soft); font-size: 12px; letter-spacing: 0.18em; 72 text-transform: uppercase; margin-bottom: 44px; font-weight: 400; 73 font-family: 'JetBrains Mono', monospace; } 74 .proof .dot { color: var(--rule); margin: 0 12px; } 75 .ctas { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 64px; } 76 .btn { display: inline-block; padding: 13px 24px; border-radius: 4px; 77 font-family: 'JetBrains Mono', monospace; font-size: 13px; 78 font-weight: 500; letter-spacing: 0.02em; 79 transition: all .18s ease; cursor: pointer; } 80 .btn.primary { background: var(--jade); color: #050609; 81 box-shadow: 0 0 0 1px var(--jade), 0 4px 24px rgba(26, 144, 88, 0.18); } 82 .btn.primary:hover { background: var(--jade-soft); color: #050609; 83 box-shadow: 0 0 0 1px var(--jade-soft), 0 6px 32px rgba(45, 187, 120, 0.32); } 84 .btn.secondary { background: transparent; color: var(--fg); 85 border: 1px solid var(--rule); } 86 .btn.secondary:hover { border-color: var(--jade-soft); color: var(--jade-soft); } 87 88 /* SIGNUP PANEL --------------------------------------------------- */ 89 .signup { display: none; margin: 0 0 64px; padding: 24px; 90 border: 1px solid var(--rule); border-left: 2px solid var(--jade); 91 background: var(--bg-elev); border-radius: 4px; 92 max-width: 640px; } 93 .signup.open { display: block; } 94 .signup .row { display: flex; flex-wrap: wrap; gap: 10px; 95 margin-top: 8px; } 96 .signup label { font-family: 'JetBrains Mono', monospace; font-size: 11px; 97 color: var(--fg-dim); letter-spacing: 0.18em; 98 text-transform: uppercase; } 99 .signup input[type=email] { flex: 1 1 280px; padding: 12px 14px; 100 background: var(--bg-code); color: var(--fg); 101 font-family: 'JetBrains Mono', monospace; 102 font-size: 13px; border: 1px solid var(--rule); 103 border-radius: 4px; outline: none; 104 transition: border-color .15s; } 105 .signup input[type=email]:focus { border-color: var(--jade-soft); } 106 .signup .help { color: var(--fg-dim); font-size: 12px; margin-top: 10px; } 107 .signup-options { display: grid; grid-template-columns: 1fr 1fr; 108 gap: 14px; } 109 .signup-options > div { background: var(--bg-code); 110 border: 1px solid var(--rule); border-radius: 5px; 111 padding: 18px; display: flex; flex-direction: column; 112 gap: 10px; } 113 .signup-options .free-option { border-left: 2px solid var(--jade); } 114 .signup-options .paid-option { border-left: 2px solid var(--amber); } 115 .signup-options h3 { font-family: 'JetBrains Mono', monospace; 116 font-size: 13px; color: var(--fg); 117 margin: 0; font-weight: 500; letter-spacing: 0.02em; } 118 .signup-options p { color: var(--fg-mid); font-size: 12.5px; 119 margin: 0 0 4px; line-height: 1.5; } 120 .signup-options input[type=email] { width: 100%; padding: 10px 12px; 121 background: var(--bg); color: var(--fg); 122 border: 1px solid var(--rule); 123 border-radius: 4px; 124 font-family: 'JetBrains Mono', monospace; 125 font-size: 12px; outline: none; } 126 .signup-options input[type=email]:focus { border-color: var(--jade-soft); } 127 .signup-options button { width: 100%; } 128 @media (max-width: 600px) { .signup-options { grid-template-columns: 1fr; } } 129 .signup .err { color: var(--amber); font-size: 12px; margin-top: 10px; 130 display: none; font-family: 'JetBrains Mono', monospace; } 131 .signup .err.show { display: block; } 132 .signup .keybox { margin-top: 10px; padding: 14px; background: var(--bg-code); 133 border: 1px dashed var(--jade); border-radius: 4px; 134 color: var(--amber); font-family: 'JetBrains Mono', monospace; 135 font-size: 13px; word-break: break-all; line-height: 1.5; } 136 .signup .copy { margin-top: 10px; } 137 .signup .ok-line { color: var(--jade-soft); font-family: 'JetBrains Mono', monospace; 138 font-size: 12px; letter-spacing: 0.06em; margin-top: 14px; } 139 .signup h3 { margin-bottom: 8px; } 140 141 /* TERMINAL MOCKUP ----------------------------------------------- */ 142 .term { background: var(--bg-term); border: 1px solid var(--rule); 143 border-radius: 6px; padding: 26px 28px; 144 font-family: 'JetBrains Mono', monospace; font-size: 13.5px; 145 line-height: 1.95; max-width: 740px; 146 box-shadow: 0 24px 80px rgba(0,0,0,.6), 147 0 0 0 1px rgba(45, 187, 120, 0.04); } 148 .term .you, .term .feed { color: var(--jade-soft); 149 text-shadow: 0 0 10px var(--jade-glow); } 150 .term .you::before, .term .feed::before { content: "> "; color: var(--jade); 151 text-shadow: 0 0 10px var(--jade-glow); } 152 .term .ok { color: var(--jade-soft); opacity: 0.95; } 153 .term .ok::before { content: "â "; color: var(--jade); } 154 .term .fire { color: var(--amber); font-weight: 500; 155 text-shadow: 0 0 12px var(--amber-glow); } 156 .term .fire::before { content: "ð¥ "; } 157 .term .gap { display: block; height: 12px; } 158 159 /* BEYOND MACHINES (operations pitch) ---------------------------- */ 160 .beyond { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; 161 margin-top: 40px; } 162 .beyond .col h3 { font-family: 'JetBrains Mono', monospace; 163 color: var(--jade-soft); font-size: 12px; 164 font-weight: 500; letter-spacing: 0.18em; 165 text-transform: uppercase; margin-bottom: 14px; } 166 .beyond .col p { color: var(--fg-mid); font-size: 14.5px; 167 line-height: 1.65; margin: 0 0 18px; 168 font-weight: 400; } 169 .term.compact { padding: 18px 20px; font-size: 12.5px; 170 line-height: 1.85; max-width: none; box-shadow: none; 171 border: 1px solid var(--rule); } 172 .beyond-foot { margin-top: 32px; color: var(--fg-mid); 173 font-size: 14px; max-width: 720px; 174 font-style: normal; } 175 .beyond-foot strong { color: var(--fg); font-weight: 500; } 176 .beyond-sub { color: var(--fg-mid); font-size: 16px; line-height: 1.55; 177 margin: 6px 0 0; max-width: 760px; font-weight: 300; } 178 @media (max-width: 720px) { 179 .beyond { grid-template-columns: 1fr; } 180 } 181 182 /* HOW IT WORKS -------------------------------------------------- */ 183 .grid3 { display: grid; gap: 36px; 184 grid-template-columns: repeat(3, 1fr); margin-top: 40px; } 185 .col h3 { display: flex; align-items: baseline; gap: 12px; } 186 .col h3 .num { color: var(--amber); font-size: 12px; letter-spacing: 0.1em; } 187 .col p { color: var(--fg-mid); font-size: 14.5px; line-height: 1.65; 188 margin: 0; font-weight: 400; } 189 190 /* CONNECTIONS --------------------------------------------------- */ 191 .pillrow { display: flex; flex-wrap: wrap; align-items: center; 192 gap: 8px 8px; margin-bottom: 22px; } 193 .pillrow .label { width: 100%; margin-bottom: 8px; } 194 .pill { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; 195 color: var(--fg-mid); background: transparent; 196 border: 1px solid var(--rule); border-radius: 3px; 197 padding: 7px 13px; font-weight: 400; 198 transition: all .15s ease; } 199 .pill:hover { color: var(--jade-soft); border-color: rgba(45,187,120,0.35); } 200 .footnote { color: var(--fg-dim); font-size: 13px; line-height: 1.7; 201 margin-top: 24px; max-width: 720px; font-weight: 400; } 202 203 /* PRICING (outlined cards) -------------------------------------- */ 204 .grid4 { display: grid; gap: 14px; 205 grid-template-columns: repeat(4, 1fr); margin: 32px 0 28px; } 206 .card { background: transparent; 207 border: 1px solid var(--rule); 208 border-top: 1px solid rgba(26, 144, 88, 0.45); 209 border-radius: 4px; padding: 26px 22px; 210 transition: border-color .2s ease, transform .2s ease; } 211 .card:hover { transform: translateY(-2px); border-top-color: var(--jade-soft); } 212 .card .name { color: var(--fg-mid); font-size: 11px; font-weight: 400; 213 letter-spacing: 0.18em; text-transform: uppercase; 214 margin-bottom: 14px; font-family: 'JetBrains Mono', monospace; } 215 .card .price { color: var(--fg); font-size: 28px; font-weight: 500; 216 margin-bottom: 12px; font-family: 'JetBrains Mono', monospace; 217 letter-spacing: -0.02em; } 218 .card .price .unit { color: var(--fg-dim); font-size: 13px; font-weight: 400; 219 letter-spacing: 0; margin-left: 2px; } 220 .card .desc { color: var(--fg-mid); font-size: 13px; line-height: 1.55; 221 font-weight: 400; } 222 .free-line { color: var(--fg-mid); font-size: 13px; line-height: 1.85; 223 font-weight: 400; max-width: 680px; margin-top: 22px; } 224 .free-line strong { color: var(--fg); font-family: 'JetBrains Mono', monospace; 225 font-weight: 500; } 226 227 /* PRICING TIERS ------------------------------------------------- */ 228 .tier-grid { display: grid; gap: 16px; margin: 32px 0 12px; 229 grid-template-columns: repeat(3, 1fr); } 230 .tier { background: var(--bg-elev); border: 1px solid var(--rule); 231 border-top: 1px solid var(--rule); 232 border-radius: 5px; padding: 26px 24px; 233 display: flex; flex-direction: column; gap: 16px; 234 transition: border-color .2s ease, transform .2s ease; } 235 .tier:hover { transform: translateY(-2px); } 236 .tier-starter { border-top: 2px solid var(--jade); 237 box-shadow: 0 0 0 1px rgba(26,144,88,.18); } 238 .tier-growth { border-top: 1px solid rgba(45,187,120,.45); } 239 .tier-enterprise{ border-top: 1px solid rgba(240,160,48,.45); } 240 .tier-head { display: flex; justify-content: space-between; align-items: baseline; } 241 .tier .name { font-family: 'JetBrains Mono', monospace; font-size: 11px; 242 color: var(--jade-soft); letter-spacing: 0.22em; 243 text-transform: uppercase; font-weight: 500; } 244 .tier-enterprise .name { color: var(--amber); } 245 .tier .badge { font-family: 'JetBrains Mono', monospace; font-size: 10px; 246 color: var(--fg-dim); letter-spacing: 0.06em; } 247 .tier .badge.recommended { color: var(--jade-soft); } 248 .tier .price-list { display: flex; flex-direction: column; gap: 6px; } 249 .tier .line { display: flex; justify-content: space-between; align-items: baseline; 250 font-family: 'JetBrains Mono', monospace; font-size: 13px; 251 color: var(--fg-mid); padding: 4px 0; 252 border-bottom: 1px dashed var(--rule-soft); } 253 .tier .line:last-child { border-bottom: none; } 254 .tier .line .what { color: var(--fg-mid); } 255 .tier .line .amt { color: var(--fg); font-weight: 500; } 256 .tier-growth .line .amt, 257 .tier-enterprise .line .amt { color: var(--jade-soft); }
258 .tier .desc { color: var(--fg-mid); font-size: 13px; line-height: 1.55; 259 margin: 0; } 260 .tier input[type=email] { width: 100%; padding: 10px 12px; 261 background: var(--bg-code); color: var(--fg); 262 border: 1px solid var(--rule); border-radius: 4px; 263 font-family: 'JetBrains Mono', monospace; 264 font-size: 12px; outline: none; box-sizing: border-box; } 265 .tier input[type=email]:focus { border-color: var(--jade-soft); } 266 .tier .cta { display: inline-block; padding: 11px 16px; border-radius: 4px; 267 font-family: 'JetBrains Mono', monospace; font-size: 12px; 268 font-weight: 500; letter-spacing: 0.04em; text-align: center; 269 transition: all .15s ease; cursor: pointer; border: none; } 270 .tier-starter .cta { background: var(--jade); color: #050609; 271 box-shadow: 0 0 0 1px var(--jade), 0 4px 18px rgba(26,144,88,.18); } 272 .tier-starter .cta:hover { background: var(--jade-soft); color: #050609; } 273 .tier-growth .cta, .tier-enterprise .cta { 274 background: transparent; color: var(--fg); border: 1px solid var(--rule); } 275 .tier-growth .cta:hover, .tier-enterprise .cta:hover { 276 border-color: var(--jade-soft); color: var(--jade-soft); } 277 .tier .hint { color: var(--fg-dim); font-size: 11px; margin: 0; 278 font-family: 'JetBrains Mono', monospace; letter-spacing: 0.04em; } 279 @media (max-width: 760px) { .tier-grid { grid-template-columns: 1fr; } } 280 281 /* INTEGRATORS --------------------------------------------------- */ 282 .integrators p { color: var(--fg-mid); max-width: 700px; 283 margin-bottom: 28px; font-size: 15.5px; font-weight: 400; 284 line-height: 1.7; } 285 .small-note { color: var(--fg-dim); font-size: 12.5px; 286 margin-top: 18px; font-style: italic; font-weight: 400; } 287 288 /* MCP / CODE ---------------------------------------------------- */ 289 pre.code, pre { background: var(--bg-term); border: 1px solid var(--rule); 290 border-radius: 6px; padding: 18px 22px; 291 font-family: 'JetBrains Mono', monospace; font-size: 12.5px; 292 color: var(--fg); overflow-x: auto; line-height: 1.55; 293 margin: 12px 0; max-width: 740px; 294 box-shadow: 0 16px 48px rgba(0,0,0,.4); } 295 pre code { color: var(--fg); font-size: inherit; } 296 pre.code .key { color: var(--amber); } 297 pre.code .str { color: var(--jade-soft); } 298 .mcp-summary { color: var(--fg-mid); font-size: 14px; margin-bottom: 22px; 299 font-weight: 400; } 300 .mcp-links a { margin-right: 24px; font-family: 'JetBrains Mono', monospace; 301 font-size: 13px; } 302 303 /* DOCS SECTION (nested below landing) --------------------------- */ 304 .docs-divider { border: 0; border-top: 1px solid var(--rule); 305 max-width: var(--max); margin: 60px auto 0; } 306 .docs-intro { color: var(--fg-mid); font-size: 14.5px; 307 margin-bottom: 32px; max-width: 720px; } 308 .docs h2 { margin-top: 56px; margin-bottom: 14px; } 309 .docs h2:first-of-type { margin-top: 0; } 310 .docs h3 { color: var(--jade-soft); margin-top: 30px; margin-bottom: 8px; } 311 .docs p { color: var(--fg-mid); font-size: 14px; line-height: 1.7; } 312 .docs ol, .docs ul { color: var(--fg-mid); font-size: 14px; } 313 314 /* LEGAL SECTION (TOS + Privacy, anchored at #terms / #privacy) -- */ 315 .legal h1 { font-family: 'JetBrains Mono', monospace; 316 color: var(--jade-soft); font-size: 24px; 317 font-weight: 500; margin: 0 0 8px; 318 letter-spacing: -0.01em; } 319 .legal h2 { color: var(--amber); font-size: 16px; 320 margin: 40px 0 12px; font-family: 'JetBrains Mono', monospace; } 321 .legal h2:first-of-type { margin-top: 24px; } 322 .legal h3 { color: var(--fg); font-size: 14px; 323 margin: 24px 0 8px; letter-spacing: 0; 324 text-transform: none; font-family: 'JetBrains Mono', monospace; } 325 .legal p { color: var(--fg-mid); font-size: 14px; line-height: 1.8; 326 margin: 0 0 14px; } 327 .legal .updated { color: var(--fg-dim); font-size: 12px; 328 margin-bottom: 32px; 329 font-family: 'JetBrains Mono', monospace; 330 letter-spacing: 0.06em; } 331 .legal hr { border: none; border-top: 1px solid var(--rule); 332 margin: 48px 0; } 333 .endpoint { border-top: 1px solid var(--rule); padding-top: 20px; 334 margin-top: 26px; } 335 .endpoint:first-of-type { margin-top: 18px; } 336 .endpoint .method { display: inline-block; color: var(--bg); 337 background: var(--jade); padding: 1px 9px; 338 border-radius: 3px; font-weight: 600; font-size: 11px; 339 vertical-align: 2px; font-family: 'JetBrains Mono', monospace; 340 letter-spacing: 0.05em; } 341 .endpoint .method.get { background: var(--amber); } 342 .endpoint .path { color: var(--fg); font-size: 14px; } 343 .endpoint .desc { color: var(--fg-mid); margin: 6px 0 12px; 344 font-size: 14px; line-height: 1.65; } 345 346 /* FOOTER (single line) ----------------------------------------- */ 347 footer { border-top: 1px solid var(--rule); padding: 28px; 348 max-width: var(--max); margin: 80px auto 0; 349 color: var(--fg-dim); font-size: 12px; text-align: center; 350 font-family: 'JetBrains Mono', monospace; font-weight: 400; 351 letter-spacing: 0.02em; line-height: 1.8; } 352 footer .sep { color: var(--rule); margin: 0 12px; } 353 footer a { color: var(--fg-mid); } 354 footer a:hover { color: var(--jade-soft); } 355 356 /* RESPONSIVE --------------------------------------------------- */ 357 @media (max-width: 760px) { 358 section { padding: 70px 22px; } 359 section.first { padding-top: 90px; } 360 .grid3 { grid-template-columns: 1fr; gap: 32px; } 361 .grid4 { grid-template-columns: 1fr 1fr; } 362 .term { font-size: 12px; padding: 20px; } 363 .hero p.sub { font-size: 18px; } 364 footer { font-size: 11px; } 365 footer .sep { margin: 0 8px; } 366 } 367 @media (max-width: 460px) { 368 .grid4 { grid-template-columns: 1fr; } 369 footer .sep.collapse { display: block; visibility: hidden; height: 4px; } 370 } 371 /* FN-NAV-CSS-OPEN */ 372 373 /* TOP NAV âââââââââââââââââââââââââââââââââââââââââââââââ */ 374 .topnav { position:sticky; top:0; z-index:8000; 375 background:rgba(8,8,13,0.92); backdrop-filter:blur(10px); 376 -webkit-backdrop-filter:blur(10px); 377 border-bottom:1px solid var(--rule-soft); 378 padding:12px 28px; display:flex; align-items:center; 379 gap:32px; } 380 .topnav-brand { font-family:'JetBrains Mono',monospace; 381 font-size:13px; font-weight:600; letter-spacing:0.02em; 382 color:var(--fg); text-decoration:none; } 383 .topnav-brand:hover { color:var(--jade-soft); } 384 .topnav-dropdown { position:relative; } 385 .topnav-dropdown summary { font-family:'JetBrains Mono',monospace; 386 font-size:12px; color:var(--fg-mid); 387 letter-spacing:0.04em; cursor:pointer; 388 list-style:none; padding:6px 10px; 389 border-radius:3px; user-select:none; 390 transition:color .15s ease; } 391 .topnav-dropdown summary::-webkit-details-marker { display:none; } 392 .topnav-dropdown summary:hover { color:var(--jade-soft); } 393 .topnav-dropdown summary::after { content:" â¾"; font-size:9px; 394 color:var(--fg-dim); margin-left:3px; } 395 .topnav-dropdown[open] summary { color:var(--jade-soft); } 396 .topnav-menu { position:absolute; top:calc(100% + 6px); left:0; 397 min-width:190px; background:var(--bg-elev); 398 border:1px solid var(--rule); border-radius:4px; 399 padding:6px; box-shadow:0 8px 24px rgba(0,0,0,0.45); 400 display:flex; flex-direction:column; gap:2px; } 401 .topnav-menu a { font-family:'JetBrains Mono',monospace; font-size:12px; 402 color:var(--fg-mid); padding:8px 12px; 403 text-decoration:none; border-radius:3px; 404 transition:all .12s ease; } 405 .topnav-menu a:hover { background:var(--bg-code); color:var(--jade-soft); } 406 .topnav-menu a.active { color:var(--jade-soft); 407 border-left:2px solid var(--jade-soft); padding-left:10px; } 408 .topnav-spacer { flex:1; } 409 .topnav-cta { font-family:'JetBrains Mono',monospace; font-size:12px; 410 color:var(--jade-soft); text-decoration:none; 411 letter-spacing:0.04em; padding:6px 10px; 412 transition:color .15s ease; } 413 .topnav-cta:hover { color:var(--amber); } 414 @media (max-width:640px) { 415 .topnav { padding:10px 14px; gap:8px 12px; flex-wrap:wrap; } 416 .topnav-spacer { flex-basis:100%; height:0; } 417 .topnav-cta { display:inline-block; font-size:12px; padding:4px 7px; } 418 } 419 420 /* FN-NAV-CSS-CLOSE */ 421 422 /* per-machine cost calculator (added 2026-05-29) */ 423 .price-calculator { 424 background: var(--bg-elev, #0c0f17); 425 border: 1px solid var(--rule, #16202e); 426 border-radius: 8px;
427 padding: 22px 26px; 428 margin: 0 auto 28px; 429 max-width: 760px; 430 } 431 .price-calculator .calc-intro { 432 margin: 0 0 14px; 433 font-size: 13px; 434 color: var(--fg-mid, #8d99ad); 435 letter-spacing: .04em; 436 text-transform: uppercase; 437 } 438 .price-calculator .calc-grid { 439 display: grid; 440 grid-template-columns: repeat(3, 1fr); 441 gap: 14px; 442 } 443 .price-calculator .calc-cell { 444 display: flex; 445 flex-direction: column; 446 gap: 4px; 447 padding: 14px 16px; 448 background: var(--bg, #08080d); 449 border: 1px solid var(--rule, #16202e); 450 border-radius: 6px; 451 } 452 .price-calculator .calc-cell .cad { 453 font-size: 11.5px; 454 color: var(--fg-dim, #5a6678); 455 letter-spacing: .08em; 456 text-transform: uppercase; 457 } 458 .price-calculator .calc-cell .est { 459 font-size: 18px; 460 color: var(--fg, #d8dfeb); 461 font-weight: 500; 462 } 463 .price-calculator .calc-foot { 464 margin: 14px 0 0; 465 font-size: 12px; 466 color: var(--fg-dim, #5a6678); 467 } 468 @media (max-width: 640px) { 469 .price-calculator .calc-grid { grid-template-columns: 1fr; } 470 } 471 472 /* ââ Phase 1 additions: sandbox / coverage / per-asset / about âââââââ */ 473 474 /* SANDBOX SECTION ----------------------------------------------- */ 475 .sandbox-section .sandbox-lede { 476 max-width: 720px; color: var(--fg-mid); font-size: 15px; 477 margin: 4px 0 28px; line-height: 1.65; 478 } 479 .sandbox-steps { list-style: none; padding: 0; margin: 0; 480 display: flex; flex-direction: column; gap: 18px; } 481 .sandbox-steps > li { display: flex; gap: 18px; 482 background: var(--bg-elev); 483 border: 1px solid var(--rule); 484 border-left: 2px solid var(--jade); 485 border-radius: 5px; padding: 22px 24px; } 486 .sandbox-steps .step-num { font-family: 'JetBrains Mono', monospace; 487 font-size: 13px; color: var(--jade-soft); 488 letter-spacing: 0.18em; padding-top: 2px; 489 min-width: 28px; } 490 .sandbox-steps .step-body { flex: 1; } 491 .sandbox-steps h3 { font-family: 'JetBrains Mono', monospace; 492 font-size: 13px; color: var(--fg); 493 letter-spacing: 0.02em; text-transform: none; 494 margin: 0 0 6px; font-weight: 500; } 495 .sandbox-steps p { color: var(--fg-mid); margin: 0 0 12px; 496 font-size: 14px; line-height: 1.6; } 497 .sandbox-resp { margin-top: 12px; font-size: 12.5px; } 498 .sandbox-foot { margin-top: 22px; color: var(--fg-dim); 499 font-size: 12.5px; max-width: 720px; line-height: 1.65; } 500 501 /* COVERAGE SECTION ---------------------------------------------- */ 502 .coverage-section .coverage-lede { 503 max-width: 720px; color: var(--fg-mid); font-size: 14px; 504 margin: 4px 0 26px; line-height: 1.65; 505 } 506 .oem-grid { display: grid; grid-template-columns: repeat(4, 1fr); 507 gap: 10px; margin: 0 0 22px; } 508 .oem { display: flex; flex-direction: column; gap: 6px; 509 background: var(--bg-elev); border: 1px solid var(--rule); 510 border-radius: 4px; padding: 14px 16px; } 511 .oem-name { font-family: 'JetBrains Mono', monospace; 512 font-size: 13px; color: var(--fg); font-weight: 500; 513 letter-spacing: 0.01em; } 514 .oem-tier { font-family: 'JetBrains Mono', monospace; 515 font-size: 10.5px; letter-spacing: 0.12em; 516 text-transform: uppercase; font-weight: 500; } 517 .oem-tier.prod { color: var(--jade-soft); } 518 .oem-tier.beta { color: var(--amber); } 519 .oem-tier.early { color: var(--fg-dim); } 520 .coverage-foot { color: var(--fg-mid); font-size: 12.5px; 521 max-width: 720px; line-height: 1.65; 522 border-top: 1px dashed var(--rule); padding-top: 16px; } 523 @media (max-width: 760px) { .oem-grid { grid-template-columns: repeat(2, 1fr); } } 524 525 /* PRICING (Phase 1, per-asset headline) ------------------------ */ 526 .pricing-lede { max-width: 720px; color: var(--fg-mid); 527 font-size: 14px; margin: 4px 0 26px; line-height: 1.65; } 528 .pricing-tier-grid { grid-template-columns: 1fr 1.15fr 1fr; } 529 .tier-free { border-top: 1px solid var(--rule); } 530 .tier-perasset { border-top: 2px solid var(--jade); 531 box-shadow: 0 0 0 1px rgba(26,144,88,.22), 532 0 8px 32px rgba(26,144,88,.10); } 533 .tier .price-display { display: flex; align-items: baseline; gap: 6px; 534 font-family: 'JetBrains Mono', monospace; } 535 .tier .price-display .amount { font-size: 32px; color: var(--fg); 536 font-weight: 500; letter-spacing: -0.02em; } 537 .tier .price-display .unit { font-size: 12px; color: var(--fg-dim); 538 letter-spacing: 0; } 539 .tier-features { list-style: none; padding: 0; margin: 6px 0 4px; 540 display: flex; flex-direction: column; gap: 6px; } 541 .tier-features li { color: var(--fg-mid); font-size: 13px; 542 line-height: 1.5; padding: 4px 0; 543 border-bottom: 1px dashed var(--rule-soft); } 544 .tier-features li:last-child { border-bottom: none; } 545 .tier-features strong { color: var(--fg); font-weight: 500; } 546 .tier-features code { font-size: 12.5px; } 547 .gate-tag { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; 548 letter-spacing: 0.14em; text-transform: uppercase; 549 color: var(--amber); border: 1px solid var(--amber); 550 padding: 1px 6px; border-radius: 3px; margin-left: 4px; } 551 .tier-perasset .cta { background: var(--jade); color: #050609; 552 box-shadow: 0 0 0 1px var(--jade), 553 0 4px 18px rgba(26,144,88,.20); } 554 .tier-perasset .cta:hover { background: var(--jade-soft); } 555 .onramp { display: flex; flex-direction: column; gap: 6px; 556 margin: 24px 0 4px; padding: 14px 18px; 557 background: var(--bg-code); border: 1px solid var(--rule); 558 border-radius: 4px; } 559 .onramp-label { font-family: 'JetBrains Mono', monospace; font-size: 11px; 560 color: var(--fg-mid); letter-spacing: 0.18em; 561 text-transform: uppercase; } 562 .onramp-rates { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; 563 color: var(--fg); } 564 .onramp-rates code { color: var(--jade-soft); } 565 .onramp-foot { color: var(--fg-dim); font-size: 12px; line-height: 1.55; } 566 @media (max-width: 900px) { .pricing-tier-grid { grid-template-columns: 1fr; } } 567 568 /* ABOUT + SECURITY ---------------------------------------------- */ 569 .about-section .about-grid { display: grid; 570 grid-template-columns: 1fr 1fr; gap: 28px; } 571 .about-section h3 { font-family: 'JetBrains Mono', monospace; 572 font-size: 11px; color: var(--jade-soft); 573 letter-spacing: 0.18em; text-transform: uppercase; 574 font-weight: 500; margin-bottom: 14px; } 575 .about-section .about-col p { color: var(--fg-mid); font-size: 14px; 576 line-height: 1.65; } 577 .about-section .muted { color: var(--fg-dim); font-size: 13px; } 578 .security-list { list-style: none; padding: 0; margin: 0 0 12px; 579 display: flex; flex-direction: column; gap: 6px; } 580 .security-list li { color: var(--fg-mid); font-size: 13.5px; 581 line-height: 1.55; padding: 4px 0; 582 border-bottom: 1px dashed var(--rule-soft); } 583 .security-list li:last-child { border-bottom: none; } 584 .security-list strong { color: var(--fg); font-weight: 500; } 585 @media (max-width: 760px) { .about-section .about-grid { grid-template-columns: 1fr; } } 586 587 /* hide the now-superseded calculator (left in DOM for nobody, replaced) */ 588 .price-calculator { display: none; } 589 590 /* 4-DOOR HUB ----------------------------------------------------- */ 591 .hub { display:grid; gap:16px; grid-template-columns:1fr 1fr; margin-top:30px; } 592 .product-card { border:1px solid var(--rule); border-top:2px solid var(--jade); 593 border-radius:6px; padding:22px 22px 18px; background:var(--bg-elev); 594 display:flex; flex-direction:column; } 595 .product-card h4 { font-family:'JetBrains Mono',monospace; font-size:16px; 596 font-weight:600; color:var(--fg); margin:0 0 8px; letter-spacing:-.01em; } 597 .product-card p { color:var(--fg-mid); font-size:13.5px; line-height:1.55; margin:0 0 14px; flex:1; } 598 .product-card a { font-family:'JetBrains Mono',monospace; font-size:12px; letter-spacing:.02em; } 599 @media (max-width:640px){ .hub { grid-template-columns:1fr; } } 600 601/* ââ responsive hardening: mobile horizontal-overflow fixes âââââââââââââââ */ 602/* grid/flex children default to min-width:auto and refuse to shrink below their 603 min-content width; a single long token then widens the whole document. */ 604.card{min-width:0;overflow-wrap:anywhere} 605.pill{max-width:100%;overflow-wrap:anywhere} 606table.map{display:block;overflow-x:auto;max-width:100%} 607pre,pre.code{max-width:100%} 608/* the footer template has no whitespace between links, so the line cannot wrap; 609 a zero-width space after each separator gives it a break opportunity. */ 610footer .sep::after{content:"\200B"} 611/* root-page navs only got flex-wrap inside a <768px media query, so at exactly 612 768px the nav ran 3px past the viewport instead of wrapping. */ 613.topnav{flex-wrap:wrap} 614</style> 615<!-- FN-FAVICON --> 616<link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16 32x32 48x48"> 617<link rel="icon" href="/icon-512.png" type="image/png" sizes="512x512"> 618<link rel="apple-touch-icon" href="/apple-touch-icon.png"> 619<!-- /FN-FAVICON --> 620<!-- FN-CDM-LD -->
621<script type="application/ld+json">{ 622 "@context": "https://schema.org", 623 "@type": "SoftwareApplication", 624 "name": "Forge Canonical Data Model", 625 "applicationCategory": "Industrial IoT", 626 "operatingSystem": "Docker (linux/amd64, linux/arm64)", 627 "description": "Canonical data model for industrial equipment telemetry with ISA-95 classification", 628 "url": "https://foundrynet.io/cdm/", 629 "offers": { 630 "@type": "Offer", 631 "price": "0", 632 "priceCurrency": "USD", 633 "description": "Free developer sandbox container" 634 }, 635 "publisher": { 636 "@type": "Organization", 637 "name": "Foundry Labs", 638 "url": "https://foundrynet.io" 639 } 640}</script>
640 641</head> 642<body> 643<!-- FN-NAV-OPEN --> 644<nav class="topnav"> 645 <a class="topnav-brand" href="/">FoundryNet</a> 646 <details class="topnav-dropdown"> 647 <summary>Industries</summary> 648 <div class="topnav-menu"> 649 <a href="/cnc">Manufacturing</a> 650 <a href="/datacenters">Data centers</a> 651 <a href="/energy">Energy</a> 652 <a href="/coldchain">Cold chain</a> 653 </div> 654 </details> 655 <span class="topnav-spacer"></span> 656 <a class="topnav-cta" href="https://forge.foundrynet.io">Forge</a> 657 <a class="topnav-cta" href="https://forge.foundrynet.io/pricing">Pricing</a> 658 <a class="topnav-cta" href="/cdm/">Data Model</a> 659 <a class="topnav-cta" href="/docs">Docs</a> 660 <a class="topnav-cta" href="/technology">Technology</a> 661</nav> 662<!-- FN-NAV-CLOSE --> 663<!-- FN-NAV-CLOSE --> 664 665<section class="hero first" style="padding-bottom:0;"> 666 <h1 style="font-size:clamp(30px,4vw,44px);">Developer docs</h1> 667 <p class="sub" style="font-size:18px;">The Forge API, the 32-tool MCP server, and the reliability internals. Get a free key at <a href="https://forge.foundrynet.io/pricing">forge.foundrynet.io/pricing</a>: 3 machines, no card.</p> 668</section> 669<section id="docs" class="docs"> 670 <h2>API Reference</h2> 671 <p class="docs-intro"> 672 All <code>/v1/*</code> requests need <code>Authorization: Bearer fnet_â¦</code> and (where applicable) <code>Content-Type: application/json</code>. Base URL: <code>https://forge.foundrynet.io</code>. 673 </p> 674 675 <h2>Quick start</h2> 676 <ol> 677 <li>Get a free key instantly, no email gate: <a href="https://forge.foundrynet.io/pricing">forge.foundrynet.io/pricing</a> (Sandbox: 3 machines, no card)</li> 678 <li>Identify a machine: <code>POST /v1/identify</code></li> 679 <li>Send data: <code>POST /v1/normalize</code></li> 680 <li>Connect a tool: <code>POST /v1/tools</code></li> 681 <li>Set up automation: <code>POST /v1/triggers/natural</code></li> 682 <li>Query history: <code>GET /v1/history/{machine_id}</code></li> 683 <li>Cryptographic verification: <code>POST /v1/settle</code></li> 684 </ol> 685 686 <h2>Endpoints</h2> 687 688 <div class="endpoint"> 689 <span class="method">POST</span> <code class="path">/v1/identify</code> 690 <p class="desc">Provision or look up a persistent, cryptographically verified identity (machine_id) for one machine. Idempotent on (oem, model, serial).</p> 691<pre><code>{ 692 "oem": "fanuc", 693 "model": "Robodrill α-D21MiB5", 694 "serial": "R30iB-12345", 695 "site": "Line 3" 696}</code></pre> 697<pre><code>{ 698 "machine_id": "machine_4de03b", 699 "internal_id": "fanuc:robodrill-a-d21mib5:r30ib-12345", 700 "created": true, 701 "machine": { "status": "active" }, 702 "first_seen": "2026-05-04T01:00:00Z" 703}</code></pre> 704 </div> 705 706 <div class="endpoint"> 707 <span class="method">POST</span> <code class="path">/v1/normalize</code> 708 <p class="desc">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 <code>idempotency_key</code> dedups retries within 24h. Optional <code>observed_at</code> (ISO 8601 controller clock) is stored alongside the server <code>ingested_at</code>.</p> 709<pre><code>{ 710 "data": { "Spindle_Speed": 2200, "spindle_load": 92 }, 711 "oem": "fanuc", 712 "model": "Robodrill α-D21MiB5", 713 "serial": "R30iB-12345", 714 "observed_at": "2026-05-05T09:30:15Z", 715 "idempotency_key": "optional-caller-supplied-key" 716}</code></pre> 717<pre><code>{ 718 "normalized": { "spindle_speed_rpm": 2200, "spindle_load_pct": 92 }, 719 "field_mappings": { "spindle_load": { "mapping_id": "6c34â¦", "canonical": "spindle_load_pct", "confidence": 0.93 } }, 720 "fields_total": 2, "fields_renamed": 2, "fields_identity": 0, "fields_unknown": 0, 721 "coverage_pct": 100, 722 "machine_id": "machine_4de03b", 723 "history_id": "c419â¦", 724 "triggers_fired": [{ "trigger_id": "7f0câ¦", "trigger_name": "high spindle load", "actual_value": 92 }] 725}</code></pre> 726 </div> 727 728 <div class="endpoint"> 729 <span class="method">POST</span> <code class="path">/v1/tools</code> 730 <p class="desc">Register a webhook endpoint as a tool. Triggers reference these by tool_id. <code>auth_secret</code> returned ONCE on create; never read back via GET.</p> 731<pre><code>{ 732 "name": "slack-maintenance", 733 "url": "https://hooks.slack.com/services/Tâ¦/Bâ¦/xxx", 734 "method": "POST", 735 "payload_template": { "text": "Alert: {{oem}} {{model}}, {{field}} at {{value}}" }, 736 "auth_type": "none" 737}</code></pre> 738<pre><code>{ "id": "add2â¦", "name": "slack-maintenance", "auth_type": "none", "enabled": true }</code></pre> 739 </div> 740 741 <div class="endpoint"> 742 <span class="method">POST</span> <code class="path">/v1/triggers/natural</code> 743 <p class="desc">Parse a natural-language instruction into a structured trigger. NEVER auto-activates; returns parsed_trigger for review and explicit POST to /v1/triggers.</p> 744<pre><code>{ "machine_id": "machine_4de03b", "instruction": "Alert maintenance Slack when spindle load exceeds 90." }</code></pre> 745<pre><code>{ 746 "parsed_trigger": { 747 "machine_id": "machine_4de03b", 748 "name": "Spindle Load Alert", 749 "condition": { "field": "spindle_load_pct", "op": ">", "value": 90 }, 750 "actions": [{ "tool_id": "add2â¦" }] 751 }, 752 "confirmation_required": true 753}</code></pre> 754 </div> 755 756 <div class="endpoint"> 757 <span class="method get">
757GET</span> <code class="path">/v1/history/{machine_id}</code> 758 <p class="desc">Per-machine canonical history. Query params: from, to (ISO-8601), fields (csv), limit (â¤1000), summary (bool).</p> 759<pre><code>GET /v1/history/machine_4de03b?limit=5&summary=true</code></pre> 760<pre><code>{ 761 "machine_id": "machine_4de03b", 762 "machine": { "oem": "fanuc", "model": "Robodrill α-D21MiB5", "site": "Line 3" }, 763 "row_count": 2, 764 "avg_coverage": 100, 765 "fields_covered": ["spindle_load_pct", "spindle_speed_rpm", "sensor_readings.coolant_temp"] 766}</code></pre> 767 </div> 768 769 <div class="endpoint"> 770 <span class="method">POST</span> <code class="path">/v1/settle</code> 771 <p class="desc">Create a tamper-evident, independently auditable record. Add <code>?batch=true</code> with body <code>{"machine_id": "â¦"}</code> to hash and roll up all unsettled events for that machine into one verifiable record.</p> 772<pre><code>POST /v1/settle?batch=true 773{ "machine_id": "machine_4de03b" }</code></pre> 774<pre><code>{ 775 "machine_id": "machine_4de03b", 776 "merkle_root": "d35ae2eâ¦", 777 "event_count": 4, 778 "event_types": { "identify": 1, "normalize": 3 }, 779 "period_start": "2026-08-02T21:00:00Z", 780 "period_end": "2026-08-02T22:00:00Z", 781 "settlement": "anchored", 782 "settled_at": "2026-08-02T22:00:04Z" 783}</code></pre> 784 <p class="desc">Read the machine’s verified history back with <code>GET /v1/history/{machine_id}</code>.</p> 785 </div> 786 787 <h2>MCP server</h2> 788 <p>MCP endpoint (streamable HTTP): <code>https://mcp.foundrynet.io/mcp</code></p> 789 <p>Forge exposes <strong>32 MCP tools</strong> over <code>mcp.foundrynet.io/mcp</code>, spanning normalization, prediction, operations analytics, safety guardrails, and governance. <code>GET https://mcp.foundrynet.io/health</code> and <code>GET https://forge.foundrynet.io/health</code> both report <code>32</code>. They work across 14 industrial protocols and <span data-fn="prod.oem_families">18</span> OEM families.</p> 790 791 <h3>Cloud prediction tools</h3> 792 <ul> 793 <li><code>predict_breach</code>: TimesFM forecast of <strong>when</strong> a machine exceeds a threshold, with confidence intervals</li> 794 <li><code>remaining_life</code>: remaining useful life estimate for a machine</li> 795 <li><code>fleet_health</code>: score an entire operation in one call</li> 796 <li><code>predict_batch</code>: batch fleet prediction across many machines</li> 797 <li><code>detect_anomalies</code>: surface out-of-distribution telemetry</li> 798 <li><code>machine_intelligence</code>: complete machine intelligence in one call</li> 799 </ul> 800 801 <h3>Cloud core tools</h3> 802 <ul> 803 <li><code>identify_machine</code>: provision/lookup machine_id from (oem, model, serial)</li> 804 <li><code>normalize_telemetry</code>: raw OEM data â canonical FCS, with auto-provision + trigger eval</li> 805 <li><code>query_machine_history</code>: time-series + summary over canonical_data</li> 806 <li><code>create_automation</code>: natural language â parsed_trigger (review-then-activate)</li> 807 <li><code>activate_automation</code>: arm a parsed_trigger after user confirmation</li> 808 <li><code>list_automations</code>: show all triggers configured for a machine</li> 809 <li><code>disable_automation</code>: pause a trigger without deleting it (reversible)</li> 810 <li><code>delete_automation</code>: soft delete (30-day restorable); <code>?permanent=true</code> for hard delete</li> 811 <li><code>restore_automation</code>: undo a soft delete within 30 days</li> 812 <li><code>query_webhook_history</code>: HTTP status, retry counts, latency for a trigger's deliveries</li> 813 <li><code>verify_on_chain</code>: create a tamper-evident record (single payload OR batched)</li> 814 </ul> 815 816 <h2>Reliability + record integrity</h2> 817 818 <h3>Soft delete</h3> 819 <p><code>DELETE /v1/triggers/{id}</code> defaults to soft delete, sets <code>deleted_at</code>, hides from list/eval, restorable for 30 days via <code>PATCH /v1/triggers/{id}/restore</code>. Add <code>?permanent=true</code> for irrecoverable hard delete.</p> 820 821 <h3>Idempotency</h3> 822 <p><code>/v1/normalize</code> accepts an optional <code>idempotency_key</code>. If absent, server synthesizes <code>sha256(machine_id + canonical(data))[:32]</code>. Repeats within 24h return the original response with <code>deduplicated: true</code> and skip trigger evaluation.</p> 823 824 <h3>Coverage metric</h3> 825 <p>Every <code>/v1/normalize</code> response carries three counters: <code>fields_renamed</code> (source != canonical), <code>fields_identity</code> (source == canonical), <code>fields_unknown</code> (no mapping). <code>coverage_pct = (renamed + identity) / total</code>.</p> 826 827 <h3>Record timestamps</h3> 828 <p><code>observed_at</code> (ISO 8601 from the controller clock) is optional on <code>/v1/normalize</code>. Stored alongside <code>ingested_at</code> (server). When the difference exceeds 60s, response includes <code>clock_skew_warning</code>. Sustained-condition windows reference <code>observed_at</code> when present.</p> 829 830 <h3>Structured errors</h3> 831<pre><code>{ 832 "error": true, 833 "status": 422, 834 "field": "body.oem", 835 "reason": "Field required", 836 "received_value": {}, 837 "suggestion": "e.g. 'fanuc'", 838 "additional_errors": [ { "field": "body.model", "reason": "Field required" } ] 839}</code></pre> 840 841 <h2 id="system-requirements">System requirements</h2> 842 <p>The Forge kernel runs as a Docker container on any Linux host: cloud, on-premise server, industrial PC, or edge gateway.</p> 843 844 <h3>Minimum (edge deployment)</h3> 845<pre><code>CPU: 2 cores, x86_64 or ARM64 846RAM: 4 GB 847Storage: 10 GB available 848OS: Linux (Ubuntu 20.04+, Debian 11+, Amazon Linux 2) 849Network: Ethernet to OT network (for Modbus / OPC UA / SNMP / BACnet) 850 Optional internet for cloud sync and updates 851Runtime: Docker 20.10+ or AWS Greengrass V2</code></pre> 852 853 <h3>Recommended (production)</h3> 854<pre><code>CPU: 4 cores 855RAM: 8 GB 856Storage: 50 GB (accommodates extended telemetry history) 857Network: 1 Gbps to OT network + internet for CMMS and updates</code></pre> 858 859 <h3>Cloud deployment</h3> 860 <p>Any container host: Railway, AWS ECS, GCP Cloud Run, Azure Container Apps. No special hardware. Connects to equipment via API or protocol bridge.</p> 861 862 <h3>Resource profile</h3> 863<pre><code>Container image: ~2.2 GB (compressed ~900 MB) 864Runtime memory: ~1.1 GB RSS steady state, ~1.5 GB peak 865CPU at idle: < 5% single core 866CPU during predict: ~40% single core for 2-3 seconds 867Bandwidth: < 1 MB/hour per machine at 1 reading/second</code></pre> 868 869 <h3>What is in the 1.1 GB</h3> 870<pre><code>Normalization engine (BGE-M3 embeddings): ~600 MB 871Prediction engine (TimesFM): ~400 MB 872Application + vertical packs + schema: ~100 MB</code></pre> 873 874 <h3>Supported protocols</h3> 875<pre><code>MQTT / Sparkplug B (push, real-time streaming) 876Modbus RTU / TCP (poll, legacy PLCs and sensors) 877OPC UA (subscribe, modern controllers) 878SNMP (poll, servers and network equipment) 879BACnet/IP (subscribe, building automation) 880ROS2 / DDS (subscribe, robotics and AMR fleets) 881J1939 / CAN (listen, vehicles and heavy equipment) 882MAVLink (listen, drones and aerial vehicles) 883REST API (push or pull, any HTTP-capable device) 884CSV upload (batch, historical data import)</code></pre> 885 886 <h3>No new hardware required</h3> 887 <p>Forge connects to your existing sensors, PLCs, and controllers through the protocols they already speak. No proprietary gateways, no sensor replacements, no wiring changes.</p> 888 889 <h2>Pricing</h2> 890 <p><strong style="color:var(--fg)">Building on Forge?</strong> The sandbox is free and runs on your own machine (<code>docker pull ghcr.io/foundrynet/forge-sandbox</code>). Direct API integration is $0.30 per 1,000 normalized telemetry events, on graduated tiers. Embedding the engine in a platform you sell is <a href="https://foundrynet.io/licensing">usage-based licensing</a> at $0.15 per 1,000 events, graduating to $0.03 at scale. Full rate card at <a href="https://forge.foun
890drynet.io/pricing">forge.foundrynet.io/pricing</a>.</p> 891 <p style="margin-top:18px;">The rates below are the <strong>metered</strong> option for developers and AI agents making occasional queries, not monitoring machines (that's the flat plan above). Query <code>GET /v1/usage</code> for live counts and an estimated bill.</p> 892 <p style="margin-top:10px;">A <strong>Normalized Telemetry Event (NTE)</strong> is each individual tag-value pair submitted for resolution: a request carrying N tag-value pairs is N NTEs. Normalize bills on graduated tiers per 1,000 NTE: the first 100M events each month bill at the first-tier rate regardless of total volume, and only events above each threshold bill at the next rate.</p> 893 <ul> 894 <li><code>POST /v1/normalize</code>: <strong>$0.30 per 1,000 NTE</strong>, graduating to $0.06 per 1,000 above 50B/month</li> 895 <li>Trigger fire (per webhook delivery, only on 2xx), <strong>5¢</strong></li> 896 <li><code>POST /v1/settle?batch=true</code>: <strong>2¢</strong> per batch verified (skipped verifications are free)</li> 897 <li><code>GET /v1/history/{machine_id}</code>: free</li> 898 <li><code>POST /v1/identify</code>: free</li> 899 <li><code>POST /v1/triggers/natural</code>: free (setup step; revenue comes from the trigger fires it produces)</li> 900 <li><code>POST /v1/feedback/{mapping_id}/confirm</code> and <code>/correct</code>: free</li> 901 <li>Trigger evaluation (the eval pass during <code>/v1/normalize</code>), free; you only pay for fires that successfully deliver</li> 902 </ul> 903 <p>Get a key instantly, no email gate: <a href="https://forge.foundrynet.io/pricing">start free or go Production at forge.foundrynet.io/pricing</a>. Site licenses for integrators: <a data-email href="#">get in touch</a>.</p> 904</section> 905 906<section id="enterprise" class="about-section"> 907 <h2>Enterprise</h2>
908 <div class="about-grid"> 909 <div class="about-col"> 910 <h3>Fleet-scale predictive intelligence</h3> 911 <p> 912 Per-machine deployment via AWS Greengrass. Cross-OEM normalization for 913 mixed-vendor factories. Batch fleet prediction and remaining-life estimation 914 across your entire operation, every result on a tamper-evident audit trail. 915 </p> 916 <p class="muted"> 917 Contact: <a data-email href="#">email us</a> 918 </p> 919 </div> 920 <div class="about-col"> 921 <h3>Security</h3> 922 <ul class="security-list"> 923 <li><strong>Fernet symmetric encryption</strong> on webhook auth secrets at rest.</li> 924 <li><strong>HMAC-SHA256</strong> signing on every outbound webhook delivery.</li> 925 <li><strong>Supabase Row Level Security</strong> isolates accounts at the database level.</li> 926 <li><strong>API keys hashed</strong> (SHA-256), we store the hash, not the key.</li> 927 <li><strong>Idempotency by content hash</strong> on <code>/v1/normalize</code> prevents duplicate processing.</li> 928 </ul> 929 <p class="muted">Full detail in the <a href="/privacy">Privacy Policy</a>.</p> 930 </div> 931 </div> 932</section> 933 934<!-- ââ FOOTER ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ --> 935<!-- FN-SUBSTACK-FOOTER --> 936<div style="text-align:center; padding:1.5rem 0; border-top:1px solid #333;"> 937 <a href="https://substack.com/@themachineagent" target="_blank" rel="noopener" 938 style="color:#8b949e; text-decoration:none; font-size:14px;"> 939 Get the thesis behind this infrastructure: <span style="color:#58a6ff;">The Machine Agent</span>, weekly. 940 </a> 941</div> 942<!-- /FN-SUBSTACK-FOOTER --> 943<footer> 944 Foundry Labs<span class="sep">·</span><a data-email href="#" class="foot-mail">contact</a><span class="sep collapse">·</span><a href="/docs">Docs</a><span class="sep">·</span><a href="/terms">Terms</a><span class="sep">·</span><a href="/privacy">Privacy</a><span class="sep">·</span><a href="https://assay.foundrynet.io">Assay</a> 945 <span class="sep">·</span><a href="https://substack.com/@themachineagent" target="_blank">The Machine Agent</a> 946</footer> 947
948<script> 949 (function(){ 950 var e = ['forge','foundrynet.io'].join('@'); 951 document.querySelectorAll('[data-email]').forEach(function(el){ 952 el.textContent = e; el.setAttribute('href', 'mailto:' + e); 953 }); 954 })(); 955</script>
955 956<!-- FN-COPY-BTN-OPEN --> 957<style> 958/* click-to-copy on code blocks and terminal demos, no dependencies */ 959.fn-cb { position: relative; display: block; max-width: 100%; } 960/* reserve a gutter so a long single-line command never runs under the button */ 961.fn-cb > .fn-cb-block { padding-right: 86px; } 962.fn-cb-btn { 963 position: absolute; top: 8px; right: 8px; z-index: 3; 964 font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace; 965 font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; 966 line-height: 1; padding: 6px 9px; border-radius: 5px; cursor: pointer; 967 color: #7c889c; background: #0d1219; border: 1px solid #1e2b3d; 968 -webkit-appearance: none; appearance: none; 969 /* opaque, never translucent: long commands scroll UNDER this button, and a 970 see-through chip lets that text bleed through and reads as a glitch */ 971 box-shadow: -10px 0 14px -6px rgba(0,0,0,.95); 972 transition: color .15s ease, border-color .15s ease, background .15s ease; 973} 974.fn-cb:hover .fn-cb-btn { color: #b6c0cf; } 975.fn-cb-btn:hover { color: #d8dfeb; border-color: #1a9058; background: #0f1720; } 976.fn-cb-btn:focus-visible { outline: 1px solid #2dbb78; outline-offset: 2px; color: #d8dfeb; } 977.fn-cb-btn.is-copied { color: #2dbb78; border-color: #1a9058; } 978.fn-cb-btn.is-failed { color: #f0a030; border-color: #f0a030; } 979@media (max-width: 600px) { 980 .fn-cb-btn { top: 6px; right: 6px; padding: 5px 7px; font-size: 10px; letter-spacing: .06em; } 981 .fn-cb > .fn-cb-block { padding-right: 66px; } 982} 983@media print { .fn-cb-btn { display: none; } } 984</style>
985<script> 986(function () { 987 'use strict'; 988 989 /* Terminal demos interleave commands (.you) with output (.ok/.feed) and 990 blank spacers (.gap). Copy only the FIRST contiguous run of command lines 991 so a click yields something pasteable, never a command plus its output. */ 992 function termText(el) { 993 var kids = el.children, lines = [], started = false; 994 for (var i = 0; i < kids.length; i++) { 995 var isCmd = kids[i].classList.contains('you'); 996 if (isCmd) { lines.push(kids[i].textContent); started = true; } 997 else if (started) { break; } 998 } 999 return lines.length ? lines.join('\n') : null; 1000 } 1001 1002 function clean(s) { 1003 /* indents render fine but break a shell paste */ 1004 return s.replace(/\u00a0/g, ' ').replace(/[ \t]+$/gm, '').replace(/\s+$/, ''); 1005 } 1006 1007 function payload(el) { 1008 var raw = el.classList.contains('term') ? termText(el) : el.textContent; 1009 if (!raw) return null; 1010 raw = clean(raw); 1011 return raw ? raw : null; 1012 } 1013 1014 function legacyCopy(text) { 1015 try { 1016 var ta = document.createElement('textarea'); 1017 ta.value = text; 1018 ta.setAttribute('readonly', ''); 1019 ta.style.cssText = 'position:fixed;top:0;left:-9999px;opacity:0'; 1020 document.body.appendChild(ta); 1021 ta.select(); 1022 ta.setSelectionRange(0, ta.value.length); 1023 var ok = document.execCommand('copy'); 1024 document.body.removeChild(ta); 1025 return ok; 1026 } catch (e) { return false; } 1027 } 1028 1029 function flash(btn, ok) { 1030 btn.textContent = ok ? 'Copied!' : 'Press \u2318C'; 1031 btn.classList.remove('is-copied', 'is-failed'); 1032 btn.classList.add(ok ? 'is-copied' : 'is-failed'); 1033 clearTimeout(btn._fnTimer); 1034 btn._fnTimer = setTimeout(function () { 1035 btn.textContent = 'Copy'; 1036 btn.classList.remove('is-copied', 'is-failed'); 1037 }, 2000); 1038 } 1039 1040 function copy(text, btn) { 1041 if (navigator.clipboard && navigator.clipboard.writeText && window.isSecureContext) { 1042 navigator.clipboard.writeText(text).then( 1043 function () { flash(btn, true); }, 1044 function () { flash(btn, legacyCopy(text)); } 1045 ); 1046 } else { 1047 flash(btn, legacyCopy(text)); 1048 } 1049 } 1050 1051 function attach(el) { 1052 if (el.getAttribute('data-fn-cb')) return; 1053 var text = payload(el); 1054 if (!text) return; 1055 el.setAttribute('data-fn-cb', '1'); 1056 el.classList.add('fn-cb-block'); 1057 1058 /* Wrap rather than position inside: pre/.term are overflow-x:auto, so a 1059 button parented to them would scroll away with the content. */ 1060 var wrap = document.createElement('div'); 1061 wrap.className = 'fn-cb'; 1062 el.parentNode.insertBefore(wrap, el); 1063 wrap.appendChild(el); 1064 1065 var btn = document.createElement('button'); 1066 btn.type = 'button'; 1067 btn.className = 'fn-cb-btn'; 1068 btn.textContent = 'Copy'; 1069 btn.setAttribute('aria-label', 'Copy code to clipboard'); 1070 btn.addEventListener('click', function (e) { 1071 e.preventDefault(); 1072 copy(text, btn); 1073 }); 1074 wrap.appendChild(btn); 1075 } 1076 1077 function init() { 1078 var nodes = document.querySelectorAll('pre, .term'); 1079 for (var i = 0; i < nodes.length; i++) attach(nodes[i]); 1080 } 1081 1082 if (document.readyState === 'loading') { 1083 document.addEventListener('DOMContentLoaded', init); 1084 } else { 1085 init(); 1086 } 1087})(); 1088</script>
1088 1089<!-- FN-COPY-BTN-CLOSE -->
1090<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"7d6d2efd170341a38bb6c5e09af862b7","r":1,"spa":2}' crossorigin="anonymous"></script>
vendor: 1 bytes, line 1090
1090
1091<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a44ef1f6ce4a7e38',t:'MTc5MTA2MTk0Nw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
1091</body> 1092</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.