/iblai-vibe-api
First time here? If iblai.env has no ARCHITECTURE=, run /iblai-vibe-start first (four questions; two minutes) — it decides single-org / multi-org / headless and who signs in, and every skill reads the answer.
Every /iblai-vibe-* skill mounts an SDK component. When none exists for
what the user wants, do not build a workaround in the browser — call the
platform's REST API from a Next.js route handler with the org's Platform API
Token. Everything the platform can do is reachable that way; the
iblai-api-* skills (kind api, same repo) document each endpoint
(method, URL, body, errors).
Common setup (brand, conventions, env files, verification): see docs/skill-setup.md.
Terms: docs/glossary.md.
The one rule
| Where the code runs |
Credential |
Header |
Use for |
| Browser (client components) |
the signed-in user's session token, attached by the SDK automatically |
Authorization: Token <dm_token> |
everything an SDK hook or component offers; acts as the user, with the user's permissions |
| Server (route handlers, server actions) |
IBLAI_API_KEY (= TOKEN in iblai.env) via config.apiKey() |
Authorization: Api-Token <key> |
anything without a hook, and anything that needs the org's authority (admin writes, cross-user reads, creating agents, sending notifications) |
Server, OpenAI-compatible /v1 only |
the same key |
Authorization: Bearer <key> |
chat completions / model listing on https://asgi.data.<domain>/api/ai-mentor/orgs/<org>/v1 |
Never prefix the key with NEXT_PUBLIC_, never read it outside server files,
never send it to the browser. config.apiKey() returns "" in the browser
by design.
Step 1: Install the helper
Render assets/platform.ts.j2 → lib/iblai/platform.ts.
It exports:
platformFetch(path, init?) — server-only fetch against
https://api.<DOMAIN> with the Api-Token header, JSON in/out, and a
typed PlatformError carrying the platform's status and body.
verifyCaller(req) — reads the Authorization: Token <dm_token> the
browser forwards, calls GET /dm/api/core/token/verify/, and returns the
caller's username; null when the token is missing or rejected.
requireAdmin(req) — verifyCaller plus an org-membership check that the
caller is an admin of NEXT_PUBLIC_MAIN_TENANT_KEY (via
GET /dm/api/core/platform/users/?platform_key=&query=<username>), or a
401/403 NextResponse.
The browser side sends its token like this (already how vibe-starter's
lib/iblai/metadata.ts does it):
const token = localStorage.getItem("dm_token") ?? "";
await fetch("/api/admin/whatever", {
method: "POST",
headers: { Authorization: `Token ${token}`, "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
Step 2: Write the route
Render assets/route-example.ts.j2 →
app/api/admin/example/route.ts as the pattern to copy: verify the caller,
validate the body, call the platform, return its answer, map errors.
Status mapping to keep: platform 401 → your 401; 403 → 403 (not an
admin / not allowed); 404 → 404; 429 → 429 (spend cap hit — pass the
body through, it names the interval); anything else → 502 with the
platform's message.
Three worked examples
A · An admin writes another user's metadata
Only org admins may target &username=<other>; the SDK hook has no such
parameter, so it is a server call.
// inside a route handler, after requireAdmin(req)
await platformFetch(
`/dm/api/core/users/platform-metadata/?platform_key=${org}&username=${encodeURIComponent(target)}`,
{ method: "PATCH", body: { metadata: { role_label: "mentor" }, delete_keys: [] } },
);
Reference: profile-metadata.
B · Create an agent
const agent = await platformFetch<{ unique_id: string }>(
`/dm/api/ai-mentor/orgs/${org}/users/${caller.username}/mentor-with-settings/`,
{
method: "POST",
body: {
template_name: "ai-mentor",
new_mentor_name: name,
display_name: name,
description,
system_prompt: systemPrompt,
},
},
);
// agent.unique_id is the UUID every other agent skill needs
Reference: agent-create; the full UI pattern is /iblai-vibe-agent-create.
C · Send a notification to a user
await platformFetch(`/dm/api/notifications/orgs/${org}/send/`, {
method: "POST",
body: { username: target, title: "Welcome", body: "Your account is ready." },
});
Confirm the exact path and body in
notification
before shipping — notification sending is outward-facing; confirm the
recipient list with the user first.
Which iblai-api-* skill documents what
They install with the rest of this repo's skills (npx skills add iblai/vibe --all); raw links resolve without installing.
The five families most apps read or write are marked ★.
| Need |
Skill |
| ★ Per-user custom data (preferences, flags, onboarding, app state) |
profile-metadata |
| ★ The user's own profile (name, bio, image, education, résumé) |
profile |
| ★ Agent identity, visibility, capability flags; fork; delete |
agent-setting |
| ★ Memory: global, per-agent, agent knowledge, toggles |
agent-memory |
| ★ Analytics: usage, users, topics, transcripts, costs, per-user, audit, reports |
analytics |
| Org settings (default agent, help URL, toggles, your keys) |
org |
| Users, groups, roles, policies, teams, alerts |
management, rbac |
| Invitations (single, CSV) |
invite |
| Directory sync (SCIM 2.0) |
scim |
| Create an agent; chat over REST/SSE/WebSocket; sessions |
agent-create, agent-session, agent-chat |
| Agent tabs: prompts, LLM, datasets, tools, access, embed, MCP, safety, privacy, evals, audit, history, sandbox, skills, support, disclaimers |
iblai-api-agent-<tab> — see /iblai-vibe-agent for the map |
| LLM inference with the platform key (OpenAI-compatible) |
inference |
| Search agents and content; recommendations |
search |
| Notifications: counts, inbox, mark read, send |
notification |
| Credits, paywalls, checkout, subscriptions, revenue |
billing |
| Spend caps (org / agent / user) |
spend-caps |
| Per-user feature config, app onboarding flags, trials |
feature |
| API tokens; LLM / data-source credentials |
token, integration |
| Courses, programs, catalog, milestones, credentials, media, applications |
catalog, course-create, milestone, credential, apply |
| CRM (people, deals, pipelines) |
crm |
| Third-party AI services through the platform (ElevenLabs, HeyGen) |
external-service-proxy |
| Self-hosting the backend |
infrastructure |
The schema is the contract
Before constructing any URL not copied from a skill, confirm it exists in the
live OpenAPI schema:
DOMAIN=$(grep -m1 '^DOMAIN=' iblai.env 2>/dev/null | cut -d= -f2-); DOMAIN=${DOMAIN:-iblai.app}
curl -sS -o /tmp/iblai_schema.yaml "https://api.$DOMAIN/dm/api/docs/schema/"
grep -nE "^ /api/core/users/platform-metadata" /tmp/iblai_schema.yaml
Browsable at https://api.iblai.app/dm/api/docs/. Gateway rule: DM routes
are called with the /dm prefix (/api/core/… → /dm/api/core/…); edX
routes with /lms.
Verify
pnpm typecheck and pnpm test (the helper ships with a unit test in
assets/platform.test.ts.j2 → __tests__/platform.test.ts).
- Exercise the route with a signed-in browser (the token header) — expect
401 without it, 403 as a non-admin, 200 as an admin.
- Nothing prints the key:
grep -rn "IBLAI_API_KEY" app components lib | grep -v "config.apiKey\|process.env.IBLAI_API_KEY" returns nothing.
Related skills
/iblai-vibe-user-metadata, /iblai-vibe-org-metadata, /iblai-vibe-agent-create — the three common cases, done end to end
/iblai-vibe-admin — gating admin-only routes and pages
/iblai-vibe-ops-deploy — the server env (IBLAI_API_KEY) on the hosting platform
1---2name: iblai-vibe-api3description: When there is no SDK component or hook for what the user wants, the ibl.ai REST API is fair game — this skill is the bridge. It gives the one rule (browser → SDK hooks with the session token; server → Api-Token, never in client code), a 30-line server helper, the admin-verification pattern, three worked examples (admin writes another user's metadata, create an agent, send a notification), and the map from a need to the exact `iblai-api-*` skill that documents the endpoints. Use when the user says "there's no component for", "call the API", "endpoint", "REST", "server route", "backend call", or asks for a platform feature the vibe skills don't cover. The `iblai-api-*` skills (kind api) install with this repo.4---56# /iblai-vibe-api78> **First time here?** If `iblai.env` has no `ARCHITECTURE=`, run `/iblai-vibe-start` first (four questions; two minutes) — it decides single-org / multi-org / headless and who signs in, and every skill reads the answer.910Every `/iblai-vibe-*` skill mounts an SDK component. When none exists for11what the user wants, do not build a workaround in the browser — call the12platform's REST API from a Next.js route handler with the org's Platform API13Token. Everything the platform can do is reachable that way; the14`iblai-api-*` skills (kind `api`, same repo) document each endpoint15(method, URL, body, errors).1617> **Common setup (brand, conventions, env files, verification):** see [docs/skill-setup.md](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/docs/skill-setup.md).18> Terms: [docs/glossary.md](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/docs/glossary.md).1920## The one rule2122| Where the code runs | Credential | Header | Use for |23|---|---|---|---|24| **Browser** (client components) | the signed-in user's session token, attached by the SDK automatically | `Authorization: Token <dm_token>` | everything an SDK hook or component offers; acts *as the user*, with the user's permissions |25| **Server** (route handlers, server actions) | `IBLAI_API_KEY` (= `TOKEN` in `iblai.env`) via `config.apiKey()` | `Authorization: Api-Token <key>` | anything without a hook, and anything that needs the org's authority (admin writes, cross-user reads, creating agents, sending notifications) |26| Server, OpenAI-compatible `/v1` only | the same key | `Authorization: Bearer <key>` | chat completions / model listing on `https://asgi.data.<domain>/api/ai-mentor/orgs/<org>/v1` |2728Never prefix the key with `NEXT_PUBLIC_`, never read it outside server files,29never send it to the browser. `config.apiKey()` returns `""` in the browser30by design.3132## Step 1: Install the helper3334Render [`assets/platform.ts.j2`](assets/platform.ts.j2) → `lib/iblai/platform.ts`.35It exports:3637- `platformFetch(path, init?)` — server-only `fetch` against38 `https://api.<DOMAIN>` with the `Api-Token` header, JSON in/out, and a39 typed `PlatformError` carrying the platform's status and body.40- `verifyCaller(req)` — reads the `Authorization: Token <dm_token>` the41 browser forwards, calls `GET /dm/api/core/token/verify/`, and returns the42 caller's `username`; `null` when the token is missing or rejected.43- `requireAdmin(req)` — `verifyCaller` plus an org-membership check that the44 caller is an **admin** of `NEXT_PUBLIC_MAIN_TENANT_KEY` (via45 `GET /dm/api/core/platform/users/?platform_key=&query=<username>`), or a46 `401`/`403` `NextResponse`.4748The browser side sends its token like this (already how vibe-starter's49`lib/iblai/metadata.ts` does it):5051```ts52const token = localStorage.getItem("dm_token") ?? "";53await fetch("/api/admin/whatever", {54 method: "POST",55 headers: { Authorization: `Token ${token}`, "Content-Type": "application/json" },56 body: JSON.stringify(payload),57});58```5960## Step 2: Write the route6162Render [`assets/route-example.ts.j2`](assets/route-example.ts.j2) →63`app/api/admin/example/route.ts` as the pattern to copy: verify the caller,64validate the body, call the platform, return its answer, map errors.6566Status mapping to keep: platform `401` → your `401`; `403` → `403` (not an67admin / not allowed); `404` → `404`; `429` → `429` (spend cap hit — pass the68body through, it names the interval); anything else → `502` with the69platform's message.7071## Three worked examples7273### A · An admin writes another user's metadata7475Only org admins may target `&username=<other>`; the SDK hook has no such76parameter, so it is a server call.7778```ts79// inside a route handler, after requireAdmin(req)80await platformFetch(81 `/dm/api/core/users/platform-metadata/?platform_key=${org}&username=${encodeURIComponent(target)}`,82 { method: "PATCH", body: { metadata: { role_label: "mentor" }, delete_keys: [] } },83);84```8586Reference: [profile-metadata](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-profile-metadata/SKILL.md).8788### B · Create an agent8990```ts91const agent = await platformFetch<{ unique_id: string }>(92 `/dm/api/ai-mentor/orgs/${org}/users/${caller.username}/mentor-with-settings/`,93 {94 method: "POST",95 body: {96 template_name: "ai-mentor",97 new_mentor_name: name,98 display_name: name,99 description,100 system_prompt: systemPrompt,101 },102 },103);104// agent.unique_id is the UUID every other agent skill needs105```106107Reference: [agent-create](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-create/SKILL.md); the full UI pattern is `/iblai-vibe-agent-create`.108109### C · Send a notification to a user110111```ts112await platformFetch(`/dm/api/notifications/orgs/${org}/send/`, {113 method: "POST",114 body: { username: target, title: "Welcome", body: "Your account is ready." },115});116```117118Confirm the exact path and body in119[notification](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-notification/SKILL.md)120before shipping — notification sending is outward-facing; confirm the121recipient list with the user first.122123## Which `iblai-api-*` skill documents what124125They install with the rest of this repo's skills (`npx skills add iblai/vibe --all`); raw links resolve without installing.126The five families most apps read or write are marked ★.127128| Need | Skill |129|---|---|130| ★ Per-user custom data (preferences, flags, onboarding, app state) | [profile-metadata](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-profile-metadata/SKILL.md) |131| ★ The user's own profile (name, bio, image, education, résumé) | [profile](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-profile/SKILL.md) |132| ★ Agent identity, visibility, capability flags; fork; delete | [agent-setting](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-setting/SKILL.md) |133| ★ Memory: global, per-agent, agent knowledge, toggles | [agent-memory](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-memory/SKILL.md) |134| ★ Analytics: usage, users, topics, transcripts, costs, per-user, audit, reports | [analytics](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/analytics/iblai-api-analytics/SKILL.md) |135| Org settings (default agent, help URL, toggles, your keys) | [org](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/organizations/iblai-api-org/SKILL.md) |136| Users, groups, roles, policies, teams, alerts | [management](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-management/SKILL.md), [rbac](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-rbac/SKILL.md) |137| Invitations (single, CSV) | [invite](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-invite/SKILL.md) |138| Directory sync (SCIM 2.0) | [scim](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-scim/SKILL.md) |139| Create an agent; chat over REST/SSE/WebSocket; sessions | [agent-create](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-create/SKILL.md), [agent-session](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-session/SKILL.md), [agent-chat](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-agent-chat/SKILL.md) |140| Agent tabs: prompts, LLM, datasets, tools, access, embed, MCP, safety, privacy, evals, audit, history, sandbox, skills, support, disclaimers | `iblai-api-agent-<tab>` — see `/iblai-vibe-agent` for the map |141| LLM inference with the platform key (OpenAI-compatible) | [inference](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-inference/SKILL.md) |142| Search agents and content; recommendations | [search](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-api-search/SKILL.md) |143| Notifications: counts, inbox, mark read, send | [notification](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-notification/SKILL.md) |144| Credits, paywalls, checkout, subscriptions, revenue | [billing](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/billing/iblai-api-billing/SKILL.md) |145| Spend caps (org / agent / user) | [spend-caps](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/billing/iblai-api-spend-caps/SKILL.md) |146| Per-user feature config, app onboarding flags, trials | [feature](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/users/iblai-api-feature/SKILL.md) |147| API tokens; LLM / data-source credentials | [token](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/organizations/iblai-api-token/SKILL.md), [integration](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/organizations/iblai-api-integration/SKILL.md) |148| Courses, programs, catalog, milestones, credentials, media, applications | [catalog](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/content/iblai-api-catalog/SKILL.md), [course-create](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/content/iblai-api-course-create/SKILL.md), [milestone](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/content/iblai-api-milestone/SKILL.md), [credential](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/content/iblai-api-credential/SKILL.md), [apply](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/content/iblai-api-apply/SKILL.md) |149| CRM (people, deals, pipelines) | [crm](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/organizations/iblai-api-crm/SKILL.md) |150| Third-party AI services through the platform (ElevenLabs, HeyGen) | [external-service-proxy](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/organizations/iblai-api-external-service-proxy/SKILL.md) |151| Self-hosting the backend | [infrastructure](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/ship/iblai-api-infrastructure/SKILL.md) |152153## The schema is the contract154155Before constructing any URL not copied from a skill, confirm it exists in the156live OpenAPI schema:157158```bash159DOMAIN=$(grep -m1 '^DOMAIN=' iblai.env 2>/dev/null | cut -d= -f2-); DOMAIN=${DOMAIN:-iblai.app}160curl -sS -o /tmp/iblai_schema.yaml "https://api.$DOMAIN/dm/api/docs/schema/"161grep -nE "^ /api/core/users/platform-metadata" /tmp/iblai_schema.yaml162```163164Browsable at `https://api.iblai.app/dm/api/docs/`. Gateway rule: DM routes165are called with the `/dm` prefix (`/api/core/…` → `/dm/api/core/…`); edX166routes with `/lms`.167168## Verify1691701. `pnpm typecheck` and `pnpm test` (the helper ships with a unit test in171 `assets/platform.test.ts.j2` → `__tests__/platform.test.ts`).1722. Exercise the route with a signed-in browser (the token header) — expect173 `401` without it, `403` as a non-admin, `200` as an admin.1743. Nothing prints the key: `grep -rn "IBLAI_API_KEY" app components lib | grep -v "config.apiKey\|process.env.IBLAI_API_KEY"` returns nothing.175176## Related skills177178- `/iblai-vibe-user-metadata`, `/iblai-vibe-org-metadata`, `/iblai-vibe-agent-create` — the three common cases, done end to end179- `/iblai-vibe-admin` — gating admin-only routes and pages180- `/iblai-vibe-ops-deploy` — the server env (`IBLAI_API_KEY`) on the hosting platform