Use when exploring Bknd's auto-generated API endpoints. Covers REST endpoint patterns, route listing, module base paths, SDK method mapping, admin panel API explorer, and understanding the API structure.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cameronapak-bknd-skills:bknd-api-discoveryThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Explore and understand Bknd's auto-generated REST API endpoints.
Explore and understand Bknd's auto-generated REST API endpoints.
UI steps: Admin Panel > Data > Entities
Bknd auto-generates REST endpoints for all configured modules:
┌─────────────────────────────────────────────────────────────┐
│ Bknd API Structure │
├─────────────────────────────────────────────────────────────┤
│ /api/data → CRUD for all entities │
│ /api/auth → Authentication (login, register, logout) │
│ /api/media → File uploads and serving │
│ /api/system → System operations │
│ /flow → Flow management and triggers │
│ /admin → Admin UI (if enabled) │
└─────────────────────────────────────────────────────────────┘
Use the debug command to list all registered routes:
bknd debug routes
Output:
GET /admin/*
GET /api/auth/me
POST /api/auth/password/login
POST /api/auth/logout
POST /api/auth/register
GET /api/data/:entity
POST /api/data/:entity
GET /api/data/:entity/:id
PATCH /api/data/:entity/:id
DELETE /api/data/:entity/:id
POST /api/media/upload
GET /api/media/:path
...
All entities get CRUD endpoints automatically:
| Method | Path | Description | SDK Method |
|---|---|---|---|
| GET | /api/data/:entity | List records | api.data.readMany(entity) |
| POST | /api/data/:entity/query | List (complex query) | api.data.readMany(entity, query) |
| GET | /api/data/:entity/:id | Get single record | api.data.readOne(entity, id) |
| GET | /api/data/:entity/:id/:ref | Get related records | api.data.readManyByReference(...) |
| POST | /api/data/:entity | Create record(s) | api.data.createOne/Many(entity, data) |
| PATCH | /api/data/:entity/:id | Update single | api.data.updateOne(entity, id, data) |
| PATCH | /api/data/:entity | Update many | api.data.updateMany(entity, where, data) |
| DELETE | /api/data/:entity/:id | Delete single | api.data.deleteOne(entity, id) |
| DELETE | /api/data/:entity | Delete many | api.data.deleteMany(entity, where) |
| POST | /api/data/:entity/fn/count | Count records | api.data.count(entity, where) |
| POST | /api/data/:entity/fn/exists | Check existence | api.data.exists(entity, where) |
Example: Explore posts entity
# List all posts
curl http://localhost:7654/api/data/posts
# Get post by ID
curl http://localhost:7654/api/data/posts/1
# Get with query params
curl "http://localhost:7654/api/data/posts?limit=10&sort[created_at]=desc"
# Get with relations
curl "http://localhost:7654/api/data/posts?with[]=author&with[]=comments"
# Complex query via POST
curl -X POST http://localhost:7654/api/data/posts/query \
-H "Content-Type: application/json" \
-d '{"where": {"status": "published"}, "limit": 10}'
| Method | Path | Description |
|---|---|---|
| GET | /api/auth/me | Current user info |
| POST | /api/auth/:strategy/login | Login (e.g., /api/auth/password/login) |
| POST | /api/auth/register | Register new user |
| POST | /api/auth/logout | Logout |
| GET | /api/auth/:strategy/redirect | OAuth redirect |
| GET | /api/auth/:strategy/callback | OAuth callback |
Example:
# Check current user
curl http://localhost:7654/api/auth/me \
-H "Authorization: Bearer $TOKEN"
# Login
curl -X POST http://localhost:7654/api/auth/password/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "pass123"}'
# Register
curl -X POST http://localhost:7654/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "pass123"}'
| Method | Path | Description |
|---|---|---|
| POST | /api/media/upload | Upload file |
| GET | /api/media/:path | Serve/download file |
Example:
# Upload file
curl -X POST http://localhost:7654/api/media/upload \
-H "Authorization: Bearer $TOKEN" \
-F "[email protected]"
# Serve file
curl http://localhost:7654/api/media/uploads/image.png
| Method | Path | Description |
|---|---|---|
| GET | /flow | List all flows |
| GET | /flow/:name | Get flow details |
| GET | /flow/:name/run | Manually run flow |
| * | Custom trigger path | HTTP trigger endpoints |
Example:
# List flows
curl http://localhost:7654/flow
# Run flow manually
curl http://localhost:7654/flow/my-flow/run
Access route information from your code:
import { App } from "bknd";
const app = new App({ /* config */ });
await app.build();
// Get Hono server instance
const server = app.server;
// Routes are registered on the Hono instance
// Use bknd debug routes for listing
Query the system to understand available entities:
import { Api } from "bknd";
const api = new Api({ host: "http://localhost:7654" });
// List available entities by checking which respond
const entities = ["posts", "users", "comments", "categories"];
for (const entity of entities) {
const { ok } = await api.data.readMany(entity, { limit: 1 });
if (ok) {
console.log(`Entity exists: ${entity}`);
}
}
All endpoints return consistent response format:
Success (list):
{
"data": [
{ "id": 1, "title": "Post 1" },
{ "id": 2, "title": "Post 2" }
],
"meta": {
"total": 50,
"limit": 20,
"offset": 0
}
}
Success (single):
{
"data": { "id": 1, "title": "Post 1" }
}
Error:
{
"error": {
"message": "Record not found",
"code": "NOT_FOUND"
}
}
Navigate to: http://localhost:7654/admin
Admin panel shows:
Admin panel provides:
| Parameter | Example | Description |
|---|---|---|
limit | ?limit=10 | Max records to return |
offset | ?offset=20 | Skip N records |
sort[field] | ?sort[created_at]=desc | Sort by field |
where[field] | ?where[status]=published | Filter by field |
with[] | ?with[]=author | Include relation |
join[] | ?join[]=author | Join relation (same result) |
select[] | ?select[]=id&select[]=title | Select specific fields |
curl -X POST http://localhost:7654/api/data/posts/query \
-H "Content-Type: application/json" \
-d '{
"where": {
"status": "published",
"views": { "$gt": 100 }
},
"sort": { "created_at": "desc" },
"limit": 10,
"offset": 0,
"with": ["author", "category"]
}'
import { Api } from "bknd";
const api = new Api({ host: "http://localhost:7654" });
// Method → Endpoint
api.data.readMany("posts") // GET /api/data/posts
api.data.readOne("posts", 1) // GET /api/data/posts/1
api.data.createOne("posts", {}) // POST /api/data/posts
api.data.updateOne("posts", 1, {})// PATCH /api/data/posts/1
api.data.deleteOne("posts", 1) // DELETE /api/data/posts/1
api.auth.login("password", {}) // POST /api/auth/password/login
api.auth.register({}) // POST /api/auth/register
api.auth.logout() // POST /api/auth/logout
api.auth.me() // GET /api/auth/me
api.media.upload(file) // POST /api/media/upload
# Check if API is running
curl http://localhost:7654/api/auth/me
# Returns user info or 401
# Try common entity names
for entity in posts users comments products orders; do
echo "Testing $entity..."
curl -s -o /dev/null -w "%{http_code}" http://localhost:7654/api/data/$entity
echo ""
done
async function discoverApi(host: string) {
const api = new Api({ host });
console.log("API Discovery Report");
console.log("===================");
// Test auth
const { ok: authOk } = await api.auth.me();
console.log(`Auth endpoint: ${authOk ? "working" : "requires auth"}`);
// Test common entities
const testEntities = ["posts", "users", "comments", "products"];
for (const entity of testEntities) {
const { ok, meta } = await api.data.readMany(entity, { limit: 1 });
if (ok) {
console.log(`Entity "${entity}": ${meta?.total ?? "?"} records`);
}
}
}
discoverApi("http://localhost:7654");
Problem: 404 errors on API calls
Fix: Use correct base paths:
# WRONG
curl http://localhost:7654/data/posts
curl http://localhost:7654/posts
# CORRECT
curl http://localhost:7654/api/data/posts
Problem: Login fails
Fix: Include strategy name:
# WRONG
curl -X POST http://localhost:7654/api/auth/login
# CORRECT (password strategy)
curl -X POST http://localhost:7654/api/auth/password/login
Problem: Complex queries don't work via GET
Fix: Use POST for complex queries:
# Limited filtering via GET
curl "http://localhost:7654/api/data/posts?where[status]=published"
# Complex filtering via POST
curl -X POST http://localhost:7654/api/data/posts/query \
-H "Content-Type: application/json" \
-d '{"where": {"$or": [{"status": "published"}, {"featured": true}]}}'
Problem: 404 on entity endpoints
Fix: Use exact entity names (case-sensitive, usually lowercase):
# WRONG
curl http://localhost:7654/api/data/Posts
curl http://localhost:7654/api/data/post
# CORRECT
curl http://localhost:7654/api/data/posts
Problem: POST/PATCH returns 400
Fix: Include Content-Type header:
# WRONG
curl -X POST http://localhost:7654/api/data/posts \
-d '{"title": "Test"}'
# CORRECT
curl -X POST http://localhost:7654/api/data/posts \
-H "Content-Type: application/json" \
-d '{"title": "Test"}'
| Module | Base Path | Key Operations |
|---|---|---|
| Data | /api/data | CRUD for all entities |
| Auth | /api/auth | Login, register, logout, me |
| Media | /api/media | Upload, serve files |
| Flows | /flow | List, view, run flows |
| Admin | /admin | Admin UI |
DO:
bknd debug routes to list all endpoints/query endpoint for complex filtersDON'T:
/api/ prefix on API paths/api/auth/password/login)npx claudepluginhub joshuarweaver/cascade-code-general-misc-3 --plugin cameronapak-bknd-skillsGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.