How it works
Three surfaces. Every request checked. Zero shared secrets.
Sentinel Hub keeps the public site, the secure dashboard, and the private AI API deliberately separate — so students see a guided checklist, administrators see a control plane, and provider credentials see nobody at all.
The three surfaces
Website, dashboard, gateway
The website
Explains the service, hosts the documentation and compatibility guides, and handles sign-in. Everything here is safe for the open internet — because nothing sensitive lives here.
The dashboard
The control plane: users, devices, API keys, allowed models, quotas, and usage reports. Students see their own view; administrators see their tenant; nobody sees anyone else’s.
The AI gateway
The data plane: an OpenAI-compatible API reachable only over the private network. It receives requests, applies policy, routes to an approved provider, streams the answer back, and records usage metadata.
The student journey
From sign-in to first response
Onboarding is a guided checklist in the dashboard — five steps, each one confirming before the next.
-
Sign in
Students sign in to the Sentinel dashboard with their institutional account — multi-factor authentication if campus policy requires it — and immediately see which models and features their enrollment allows.
-
Enroll a device
Name a laptop or workstation and download a one-time private-network profile for the official WireGuard client. Sentinel confirms the first successful connection.
-
Create a scoped key
Generate a Sentinel API key for each application — optionally limited to specific models and devices, with an expiration date. The full key is shown exactly once, and can be revoked at any moment.
-
Configure the app
Three values make any compatible app work: the Sentinel base URL, the Sentinel key, and an allowed model ID copied from the Models page. No provider account, no provider key, ever.
-
Build and monitor
The app can call AI. The dashboard shows live usage, remaining limits, recent errors with request IDs, and the status of every key and device.
Every single request
What happens between the app and the answer
The core security rule is simple: the private network authorizes entry, and Sentinel policy authorizes the AI action. Both are required. A stolen key is useless off the private path; network access alone can’t invoke a model. Between arrival and answer, every request passes the full sequence:
| Check | The question Sentinel answers |
|---|---|
| Network | Did the request arrive through the approved private path? |
| Credential | Is the Sentinel key valid, active, and unexpired? |
| Identity | Which tenant, student, and device own this request? |
| Permission | Does this key allow this endpoint and this exact model? |
| Capacity | Are request, token, cost, and concurrency limits available? |
| Provider | Is the configured upstream provider healthy and enabled? |
| Accounting | What usage was consumed, and what metadata gets recorded? |
Approved requests stream back in a stable, OpenAI-compatible format. Rejected requests return a clear error code, a human-readable message, and a request ID for support — never a raw stack trace, an internal address, or a provider secret.
For developers
If your app speaks OpenAI, it speaks Sentinel
Models are exposed as stable, readable Sentinel IDs — sentinel/general-fast, sentinel/code-best — so coursework doesn’t break every time a provider renames something. The signed-in Models page lists exactly what each key can call, along with capabilities like streaming, embeddings, vision, and context limits.
Any application that accepts a custom OpenAI-compatible base URL, a bearer key, and a model name can usually connect with minimal changes. The one hard limitation: apps that hard-code OpenAI’s public endpoint can’t connect directly — the docs include a compatibility checklist so nobody wastes an afternoon finding that out.
# Any OpenAI-compatible client works
from openai import OpenAI
client = OpenAI(
api_key="sent_live_EXAMPLE",
base_url="https://api.sentinel.nsend.net/v1",
)
response = client.chat.completions.create(
model="sentinel/general-fast",
messages=[{"role": "user",
"content": "Give me three study tips."}],
)
