Knowledge SpacesDeveloper Platform

Build on Knowledge Spaces

Build your product on the governed control layer behind Knowledge Spaces: isolated tenants, scoped retrieval, and audited model calls out of the box. Register with your organization name, connect your model key, and make your first API call in minutes.

your first call
$ curl -X POST https://spaces.sprinklenet.com/api/bots/<bot_id>/chat \
    -H "Content-Type: application/json" \
    -H "X-API-Key: ks_live_••••••••" \
    -d '{ "session_id": "demo-001", "text": "What should I read first?" }'

200 OK
{
  "success": true,
  "text": "Start with the implementation brief..."
}
# a 200 means your organization key and bot are working. 
Workspace on Signup Organization API Key Session APIs and Usage Controls BYOK or Managed Models
multi‑tenant
Tenants as isolated workspaces
free → paid
Limited access, then higher limits
sessions
Conversation continuity
metered
Usage-based, scales with you
From first call to production

Four Steps to Live

Sign up with your organization name, grab the Organization API Key we provision for you, then make your first bot call. No long setup, and no sales call required to start.

1

Create Your Workspace

Register with an organization name and Knowledge Spaces creates your initial workspace.

2

Connect a Model Key

Free access runs on your provider key. Add OpenAI, Anthropic, Gemini, DeepSeek, or another supported model.

3

Get Your Org Key

We create your organization and provision its API Key. Copy it from your console, keep it in your secret store, and regenerate anytime.

4

Go Live

Move to paid usage when you need higher limits, managed models, or production support.

Quickstart

Talk to a Bot in One Call

Connect a model provider key, generate your Organization API Key, then point it at a bot and get an answer grounded in your content.

POST /api/bots/<bot_id>/chat
curl -X POST https://spaces.sprinklenet.com/api/bots/<bot_id>/chat \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ks_live_••••••••" \
  -d '{ "session_id": "demo-001", "text": "What is our refund policy?" }'
const res = await fetch(
  "https://spaces.sprinklenet.com/api/bots/<bot_id>/chat",
  {
    method: "POST",
    headers: {
      "X-API-Key": "ks_live_••••••••",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ session_id: "demo-001", text: "What is our refund policy?" }),
  }
);
const data = await res.json();
import requests

res = requests.post(
    "https://spaces.sprinklenet.com/api/bots/<bot_id>/chat",
    headers={"X-API-Key": "ks_live_••••••••"},
    json={"session_id": "demo-001", "text": "What is our refund policy?"},
)
print(res.json())
Multi-Tenant by Design

One Platform, Many Tenants

Your account starts with an organization workspace. As you grow, managed organizations can separate bots, knowledge spaces, and data by customer, brand, or environment.

Organization keys, rate limits, sessions, and bots are scoped by organization, so one customer can never reach another's data.

Your platform · principal org
Tenant A
Tenant B
Tenant C
managed organizations, isolated data
end users end users end users
What you get

A Platform, Not Just an Endpoint

Everything you need to run AI knowledge agents for many tenants in production.

Multi-Tenant by Design

Organizations and managed child organizations keep each customer's data, bots, and spaces isolated.

Organization API Key

One hashed organization key for bot chat and session APIs. Regenerate it from Settings when access needs to rotate.

Session APIs

Create, continue, inspect, update, end, and delete conversation sessions through the public API.

Usage Controls

Track answer usage by organization and bot. Plans scale from free BYOK to managed model access.

Your Models or Ours

Bring your own OpenAI, Anthropic, Gemini, DeepSeek, or AWS-connected model access, or run on managed models.

Governed by Design

Every call is tenant-scoped, retrieval-bounded, and logged. It is the same control layer documented in our security white paper.

What you can build

Knowledge Agents for Any Audience

Ground answers in your own content and serve a different assistant to each customer, team, or product.

Customer Support Agents

Answer from your help center, docs, and policies, with one isolated workspace per customer.

Internal Knowledge Assistants

Answer from runbooks, wikis, and handbooks, with each team's assistant scoped to its own Spaces.

Product and Docs Q&A

Embed an assistant grounded in your documentation, in your app or your site.

Recipes

Copy, Paste, Ship

Three end-to-end walkthroughs, checked against the public OpenAPI spec. Each one goes from zero to a working call, with the response you should see and the fix for the most common failure.

1

Your First Governed Chat Call in Five Minutes

Register, generate your org API key in the console, and get a bot answer with your organization's governance (tenant isolation, logged calls) applied automatically.

1. Register and Generate Your Key

Sign up at spaces.sprinklenet.com/register with your organization name to create your workspace, then copy (or generate) your Organization API Key in Console → Settings → API Keys. It's shown once, so store it in a secret manager now.

shell
export KS_API_KEY="ks_live_your_key_here"
export BOT_ID="665f1a2b3c4d5e6f7a8b9c0d"   # from your bot in the console

2. Call the Bot

One POST with a session_id you control and the user's text.

POST /api/bots/{bot_id}/chat
curl -X POST "https://spaces.sprinklenet.com/api/bots/$BOT_ID/chat" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $KS_API_KEY" \
  -d '{ "session_id": "'"$(uuidgen)"'", "text": "What should I read first?" }'
response
200 OK
{ "success": true, "text": "Start with the implementation brief..." }

That call ran with your org's governance applied: the key is scoped to a single organization, so it can only reach bots and sessions your org owns, and the call is tenant-scoped and logged. Want tokens as they generate? Add "stream": true and the response becomes a text/event-stream of Server-Sent Events.

3. Read the Rate-Limit Headers

Every response carries RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. The default policy is 100 requests per 15 minutes per key; GET /rate-limit/info returns the live policy without authentication.

If it fails: 401 { "message": "Invalid API key" }

The key is missing, truncated, or under the wrong header. Send the full ks_live_... value as X-API-Key (or Authorization: Bearer). Lost keys can't be recovered (only a hash is stored); regenerate in the console. A 401 with a key you know is right usually means the bot id and the key belong to different organizations: a key only reaches bots its own org owns, which is the isolation working as designed. A 404 means the bot id itself doesn't exist; re-copy it from the console.

2

Sessions That Persist

Keep one conversation across many calls, then read the transcript and manage the session's lifecycle.

1. Mint an Unguessable Session Id

session_id is caller-controlled: reuse a value to continue a thread, use a new value to start fresh. A predictable id (an email, a row number) risks one user's messages landing in another user's thread inside your product, so mint a UUID per conversation.

node
const sessionId = crypto.randomUUID();
// e.g. "6b3f2c9e-8a41-4d2f-9c57-1e2a7b3d4f80"

2. Chat, Then Chat Again With the Same Id

The second call answers with the earlier turns in context.

POST /api/bots/{bot_id}/chat
const BASE = "https://spaces.sprinklenet.com/api";
const headers = {
  "X-API-Key": process.env.KS_API_KEY,
  "Content-Type": "application/json",
};

await fetch(`${BASE}/bots/${process.env.BOT_ID}/chat`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    session_id: sessionId,
    text: "My name is Dana. Which plan fits a two-person team?",
  }),
});

const followUp = await fetch(`${BASE}/bots/${process.env.BOT_ID}/chat`, {
  method: "POST",
  headers,
  body: JSON.stringify({ session_id: sessionId, text: "What was my name again?" }),
});
console.log(await followUp.json());
// { "success": true, "text": "You said your name is Dana." }

3. Retrieve the Transcript

GET /api/bots/{bot_id}/chat?session_id=...
const history = await fetch(
  `${BASE}/bots/${process.env.BOT_ID}/chat?session_id=${sessionId}`,
  { headers: { "X-API-Key": process.env.KS_API_KEY } }
);
console.log(await history.json());
response
200 OK
{
  "success": true,
  "messages": [
    { "role": "user", "content": "My name is Dana. Which plan...", "timestamp": "2026-07-08T14:03:12.000Z" },
    { "role": "assistant", "content": "For a two-person team...", "timestamp": "2026-07-08T14:03:14.000Z" }
  ]
}

4. Inspect and Manage the Session

GET /sessions/{session_id} returns the record: session_id, chatbot_id, created_at, last_active_at, message_count, status. Attach your own metadata with PUT /sessions/{session_id}/context, close with POST /sessions/{session_id}/end (transcript retained), or erase entirely with DELETE /sessions/{session_id} for GDPR erasure requests.

PUT /api/sessions/{session_id}/context
curl -X PUT "https://spaces.sprinklenet.com/api/sessions/$SESSION_ID/context" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $KS_API_KEY" \
  -d '{ "end_user_id": "user_42", "custom_context": { "plan": "enterprise" } }'
If it fails: 404 Not Found on GET /sessions/{session_id}

Sessions are created by the first chat call that uses the id; there's no separate "create session" step. Send at least one chat message with that session_id first, and check the id in the URL matches the one you chatted with exactly.

3

Verify Signed Webhooks

Subscribe to conversation and session events, verify each delivery's signature server-side, and respond so the platform marks it delivered.

1. Create the Subscription

Subscribable events: bot.conversation_started, bot.conversation_ended, session.created, session.ended, escalation.fired, plus wildcards like session.* and *. The create response includes the webhook's signing secret; store it next to your API key. On the current deployment, management calls under /orgs/{org_id}/webhooks may require a console session; if your key gets a 401 or 403, create the subscription in the console instead. Signing works identically either way.

POST /api/orgs/{org_id}/webhooks
curl -X POST "https://spaces.sprinklenet.com/api/orgs/$ORG_ID/webhooks" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $KS_API_KEY" \
  -d '{
    "name": "Ops alerting",
    "url": "https://example.com/hooks/knowledge-spaces",
    "events": ["session.ended", "escalation.fired"]
  }'

2. Know What a Delivery Looks Like

Each delivery is an HTTP POST to your URL. The signature is HMAC-SHA256, hex-encoded, computed over the string "{timestamp}.{raw body}" with your webhook secret as the key. The timestamp is Unix epoch milliseconds.

delivery
POST /hooks/knowledge-spaces
Content-Type: application/json
X-Webhook-Signature: t=1751980393000,v1=5f2d8c...e9a1
X-Webhook-Timestamp: 1751980393000
X-Webhook-Event: session.ended

{ "event_type": "session.ended", "timestamp": "2026-07-08T14:33:13.000Z", "data": { ... } }

3. Verify Every Delivery

Verify against the raw bytes before parsing, reject anything older than 5 minutes, and compare in constant time.

express receiver
import express from "express";
import crypto from "node:crypto";

const app = express();

// The signature covers the raw bytes, so use express.raw on this
// route and verify BEFORE any JSON parsing.
app.post(
  "/hooks/knowledge-spaces",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const header = req.get("X-Webhook-Signature") || "";
    const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
    const t = Number(parts.t);
    const theirs = parts.v1 || "";

    // Timestamp is Unix milliseconds. Reject anything outside 5 minutes.
    if (!t || Math.abs(Date.now() - t) > 5 * 60 * 1000) {
      return res.status(400).send("stale timestamp");
    }

    const ours = crypto
      .createHmac("sha256", process.env.KS_WEBHOOK_SECRET)
      .update(`${t}.${req.body}`) // req.body is a Buffer here
      .digest("hex");

    let valid = false;
    try {
      valid = crypto.timingSafeEqual(Buffer.from(ours), Buffer.from(theirs));
    } catch {
      valid = false;
    }
    if (!valid) return res.status(401).send("bad signature");

    const event = JSON.parse(req.body);
    console.log(req.get("X-Webhook-Event"), event.data);

    // Respond 2xx fast. Non-2xx and timeouts are retried with
    // exponential backoff (retry_count default 3, timeout_ms default 10s).
    res.sendStatus(200);
  }
);

app.listen(3000);

4. Test It, Then Debug It

POST /orgs/{org_id}/webhooks/{webhook_id}/test delivers a sample payload end to end. GET /orgs/{org_id}/webhooks/{webhook_id}/deliveries lists recent attempts with status, http_status, error_message, and next_retry_at, so you can see exactly why a delivery failed and when it retries.

If it fails: the signature never matches, even with the right secret

Almost always a raw-body problem: a global express.json() ran first and you verified a re-serialized body whose bytes differ from what was signed. Mount express.raw() on the webhook route and compute the HMAC over that Buffer. Second most common: treating t as seconds. It's Unix epoch milliseconds; compare it to Date.now() directly.

Data sovereignty

Control the Data Plane as You Grow

BYOK is available today. Customer storage and private model endpoints are Enterprise architecture options, not free-tier toggles.

Customer Storage Review

Enterprise deployments can evaluate customer-controlled object storage, region selection, encryption policy, and retention requirements.

Private Model Endpoints

For regulated teams, we can scope OpenAI-compatible private endpoints, customer cloud models, and egress controls as part of Enterprise setup.

Governed Rollout

Storage and private-model controls affect support, billing, security, and incident response, so they are configured through a managed Enterprise workflow.

Pricing

Pay for Answers, Not Seats

Start on your own model key. Move up as you need managed models, team controls, and enterprise governance. Each tier includes everything below it.

Free BYOK

$0 / month
Bring your own model key. Build in a sandbox without Sprinklenet-funded inference.
  • 500 BYOK answers / month
  • 1 initial workspace
  • Organization API key
  • Community support

Managed Team

$750 / month
Everything in Builder BYOK, plus Sprinklenet-managed models and team controls. The enterprise-ready tier, no contract required.
  • Managed models, no provider key
  • 7,500 managed answers, then $0.12 each
  • Role-based access and audit logs
  • Longer retention and prepaid balance control
  • Priority email support

Enterprise

From $2,500/mo
Everything in Managed Team, plus enterprise governance and OEM scale. For platforms, regulated teams, and high-volume deployments.
  • Role-based access, audit logs, and advanced governance; SSO and SCIM on the roadmap
  • Pooled child-org and OEM deployments
  • Own cloud or customer-controlled storage review
  • Private model endpoint architecture review

An AI Answer is one grounded reply to your user. Failed or ungrounded replies are never billed. Managed-model usage requires a positive prepaid balance after the included pool is used.

Start Building on Knowledge Spaces

Create your workspace, generate your Organization API Key, and make your first call today.

Start Building