Browse Documentation
Foundation
Platform
Capabilities
Product
Core Platform
Core Platform
Developers
Operations
Business
Billing and Plans
Billing and Plans
Start from the surface that owns the request, then push until you have a real decision receipt.
This quickstart is built from the packages that are actually in your monorepo: the core runtime SDK, 16 JavaScript wrappers, Go and Rust clients, the Python package, plus CLI and MCP surfaces for operator and agent lanes.
JavaScript wrappers
16
Framework and server packages that let the runtime layer own the request lifecycle.
Language SDKs
4
Direct clients for Go, Rust, and Python services that do not want a JS wrapper.
Operator surfaces
3
CLI, MCP, and the direct runtime SDK all share the same contract line.
Surface selection
Choose your lane
The setup gets cleaner when the package matches the real boundary: framework lifecycle, direct transport control, operator bootstrap, or agent access.
Framework adapters
Let the wrapper own the request lifecycle.
Use the framework package when middleware, hooks, or route handlers are the real policy boundary.
Direct SDK
Call the evaluator yourself.
Use the core client when transport order, response shaping, or server internals belong to your code.
Operator bootstrap
Prepare the environment from the terminal.
Persist credentials, run request probes, and audit runtime telemetry without living in the dashboard.
Agent boundary
Expose safe runtime context to models.
Use the MCP server when an agent needs evaluator access without broad system reach.
Runtime contract
Bind the contract once
Everything else stays coherent when the gateway origin, runtime key, and site id are identical across SDK, CLI, and MCP entry points.
Gateway origin
The deployed or local API origin that fronts the `/v1/dev/*` evaluator routes.
Runtime key
The request-scoped credential that authorizes evaluator calls and operator tooling.
Site id
The policy partition that keeps runtime decisions and analytics attached to the right surface.
Environment
Shared values
01COSANTOIR_GATEWAY_URL=http://localhost:400002COSANTOIR_API_KEY=dp_live_example03COSANTOIR_SITE_ID=site_prod_webConstructor map
Same contract, different client surface
01JavaScript createCosantoir({ baseUrl, apiKey, siteId })02Go cosantoir.NewClient(cosantoir.Options{ BaseURL, APIKey, SiteID })03Rust Cosantoir::new(CosantoirOptions { base_url, api_key, site_id, timeout_ms })04Python Cosantoir(CosantoirOptions(base_url=..., api_key=..., site_id=...))First live route
Wire the first route
Do one protected path end-to-end before you fan out across the rest of the framework matrix. The goal is a clean receipt, not broad but shallow coverage.
Framework wrapper
Next.js middleware
01import { createCosantoir } from "@cosantoir/node";02import { createMiddleware, readNextRequestIp } from "@cosantoir/next";03 04const client = createCosantoir({05 baseUrl: process.env.COSANTOIR_GATEWAY_URL!,06 apiKey: process.env.COSANTOIR_API_KEY!,07 siteId: process.env.COSANTOIR_SITE_ID!,08});09 10export const middleware = createMiddleware({11 client,12 failOpen: true,13 ip: (request) => readNextRequestIp(request) ?? "127.0.0.1",14});15 16export const config = {17 matcher: ["/api/protected/:path*"],18};Framework wrapper
Express middleware
01import express from "express";02import { createCosantoir } from "@cosantoir/node";03import { createDeveloperProtectionExpressMiddleware } from "@cosantoir/express";04 05const client = createCosantoir({06 baseUrl: process.env.COSANTOIR_GATEWAY_URL!,07 apiKey: process.env.COSANTOIR_API_KEY!,08 siteId: process.env.COSANTOIR_SITE_ID!,09});10 11const app = express();12app.use(13 "/protected",14 createDeveloperProtectionExpressMiddleware({ client, failOpen: true }),15);Framework wrapper
Hono middleware
01import { Hono } from "hono";02import { createCosantoir } from "@cosantoir/node";03import { createDeveloperProtectionHonoMiddleware } from "@cosantoir/hono";04 05const client = createCosantoir({06 baseUrl: process.env.COSANTOIR_GATEWAY_URL!,07 apiKey: process.env.COSANTOIR_API_KEY!,08 siteId: process.env.COSANTOIR_SITE_ID!,09});10 11const app = new Hono();12app.use("/protected/*", createDeveloperProtectionHonoMiddleware({ client }));Direct SDK
Node.js evaluator call
01import { createCosantoir } from "@cosantoir/node";02 03const client = createCosantoir({04 baseUrl: process.env.COSANTOIR_GATEWAY_URL!,05 apiKey: process.env.COSANTOIR_API_KEY!,06 siteId: process.env.COSANTOIR_SITE_ID!,07});08 09const result = await client.waf.evaluate({10 ip: "198.51.100.20",11 method: "POST",12 path: "/signup",13});14 15if (result.result.action === "deny") {16 throw new Error("request blocked");17}Verification
Verify the receipt
A working quickstart returns more than status code. You should be able to inspect the headers, correlation line, and downstream operator proof.
Probe
Send a protected request
01curl -sS -X POST http://localhost:3000/protected/signup \02 -H "content-type: application/json" \03 -H "x-forwarded-for: 198.51.100.20" \04 -d '{"email":"founder@example.com"}' -iAllow or deny result
A first request should resolve into an explicit decision, not an integration shrug.
Trace headers
Capture `x-request-id` and `x-correlation-id` so the request is explainable later.
Rate-limit receipts
Budgeted routes should emit `X-RateLimit-*` and `Retry-After` when they close.
Shared operator proof
The same request should be inspectable in dashboard views, CLI probes, and MCP tools.
Repo-wide coverage
Extend beyond JavaScript
Once the first route is real, expand into the other package surfaces that already exist in the repo instead of pretending the system ends at Node.
Go client
Direct evaluator lane
01client := cosantoir.NewClient(cosantoir.Options{02 BaseURL: os.Getenv("COSANTOIR_GATEWAY_URL"),03 APIKey: os.Getenv("COSANTOIR_API_KEY"),04 SiteID: os.Getenv("COSANTOIR_SITE_ID"),05})06 07result, err := client.EvaluateWAF(ctx, cosantoir.WafInput{08 IP: "198.51.100.20",09 Method: "POST",10 Path: "/signup",11})Rust client
Async evaluator lane
01let client = Cosantoir::new(CosantoirOptions {02 base_url: env::var("COSANTOIR_GATEWAY_URL")?,03 api_key: env::var("COSANTOIR_API_KEY")?,04 site_id: Some(env::var("COSANTOIR_SITE_ID")?),05 timeout_ms: 5000,06})?;07 08let result = client09 .evaluate_waf("198.51.100.20", "POST", "/signup")10 .await?;Python client
Service-side evaluator lane
01client = Cosantoir(02 CosantoirOptions(03 base_url=os.environ["COSANTOIR_GATEWAY_URL"],04 api_key=os.environ["COSANTOIR_API_KEY"],05 site_id=os.environ["COSANTOIR_SITE_ID"],06 )07)08 09result = client.waf_evaluate(10 ip="198.51.100.20",11 method="POST",12 path="/signup",13)App frameworks
Use the wrapper when the framework owns route resolution, middleware order, or loader execution.
Server runtimes
Use the server packages when the request path is closer to middleware, hooks, or fetch handlers.
Language SDKs
Use the language clients when your evaluator calls live outside the JavaScript wrapper family.
Operator and agent surfaces
CLI and MCP should read the same runtime contract instead of inventing their own setup logic.