Agents
Their own access. Your boundaries.
Give every agent its own database access and permissions. Each agent works with the part of your data you choose, on the same foundation as your application.
Overview
AI agents, such as shopping assistants, support bots, LLM tool-calling loops, MCP servers, and background workers, need context from your data without holding a full server key. An agent key gives one agent exactly the collections and operations its job requires.
Example policy:
| Collection | Shopping agent | Support agent |
|---|---|---|
product_catalog | read, search | read |
orders | No access | read |
support_articles | No access | read, search |
The shopping agent can query products without seeing orders or support content.
What agents can do with Singlebase:
- Read context from DocumentDB with filters and full-text search
- Query by meaning through vector docsets built for agents
- Write results back as documents, or save reports and files to Storage
- Use models for generation and embeddings with LLM, and hold chats with Conversation
- Manage users for support and ops workflows with Users
Key features:
- One named key per agent, with an
agk_prefix - Per-collection permissions:
read,search,write,delete - Per-feature permissions for LLM, files, and users
- Every operation is checked, including each item in a batch
- Enable, disable, rotate, or delete a key without touching other keys
- Usage tracked with
last_used_at - Optional expiry, extended through the existing key update operation
Use cases: Support agents that look up orders, content agents that draft and publish documents, ingestion agents that upload files, ops agents that manage users
How it works:
- Define the task - Decide what the agent should help with.
- Choose its access - Create an agent key in the console with the collections and permissions it needs.
- Connect the agent - It calls the normal API with
X-API-KEY: agk_.... - Review and adjust - Singlebase allows the call only if the key's permissions cover it. Otherwise it returns
403 AGENT_SCOPE_DENIED. Update the scope as the agent's task changes.
A project can store up to 50 agent keys.
Calling the API
Agents use the same endpoint and request format as any client. Send the agent key in X-API-KEY and no Authorization header.
Connect with MCP
Agent runtimes can also connect to https://v1.api.singlebase.io/mcp/<ENDPOINT_KEY> using Authorization: Bearer agk_… or X-API-KEY: agk_…. Enable MCP for the project first. The server lists only tools and collection choices allowed by the key and applies the same gateway rules to every call. See MCP for Claude Code, Cursor, Claude Desktop, and raw HTTP examples.
http
POST https://v1.api.singlebase.io/api/<ENDPOINT_KEY>
Content-Type: application/json
X-API-KEY: agk_<AGENT_KEY>json
{
"operation": "data.query",
"payload": {
"collection": "orders",
"filter": { "customer_email": "jane@example.com" },
"per_page": 10
}
}Within its permissions, an agent key has admin-level access:
data.queryanddata.countread across all users. Scope a request to one user with payload-level"_user_id": "<USER_ID>", alongsidefilter. Ownership fields insidefilterare rejected.data.insertcan set an owner with payload-level_user_id. A single update-by-ID can reassign an owner withdata._user_id; the user must exist. Payload-level_user_idon update selects an owner rather than changing it.- Conversations and
chat.askcan use every retrieval source, including raw collections. files.*can act on any project file.
Grant only what the agent needs.
Permissions
An agent key has two permission sets. It needs at least one entry in either.
Collection permissions
collections maps collection names to allowed actions. They apply to data.* operations using payload.collection.
json
{
"orders": ["read", "search"],
"support_notes": ["read", "write"],
"drafts": ["read", "write", "delete"]
}| Permission | Allows |
|---|---|
read | data.query, data.count, data.aggregate |
search | data.query and data.count with a non-empty search. Also grants read |
write | data.insert, data.update, data.upsert |
delete | data.archive, data.delete |
Collections that are not listed are denied. Internal system collections cannot be granted.
Operation permissions
permissions lists features the agent may use.
| Permission | Allows |
|---|---|
ai.generate | llm.generate, llm.write, llm.translate, llm.summarize, llm.categorize, llm.extract, llm.analyze |
ai.chat | All chat.* operations and their deprecated llm.* aliases, including preparation |
ai.embed | llm.embed |
files.read | files.get_signed_url |
files.list | files.query |
files.upload | files.initiate_upload, files.complete_upload, files.fail_upload, files.update, files.reprocess |
files.delete | files.delete |
users.list | users.query, users.get_details |
users.create | users.create |
users.update | users.update, users.update_status, users.update_password, users.link_provider, users.unlink_provider |
users.delete | users.delete |
For files.reprocess, agent keys always follow owner rules even with an admin role: they cannot retry another owner's file or a completed pipeline, and are limited to four starts per file. Recently active processing is refused for all callers; processing at least 30 minutes old can be restarted.
Always denied
Agent keys can never call:
auth.*anduser.*(agents don't sign in as users)users.getand the user token operations- Console operations
Batches: Every operation in a batch is checked before any runs. One denied item denies the whole request.
Docsets: In retrieval, agent keys count as agent. They can use docsets whose acl is agent, but not user or admin docsets.
Managing Agent Keys
Manage agent keys in the Singlebase console, in your project's settings. Project owners and admins can create, update, rotate, and delete them. The key secret is shown in the key field; store it right away.
Key record:
json
{
"_id": "agt_3f9a1c",
"name": "support-bot",
"description": "Answers order questions in the help widget",
"enabled": true,
"key": "agk_3f9a1c_<SECRET>",
"collections": {
"orders": ["read", "search"],
"support_notes": ["read", "write"]
},
"permissions": ["ai.chat", "files.read"],
"expires_at": "2027-01-10T12:00:00Z",
"last_used_at": "2026-10-03T12:00:00+00:00",
"_created_at": "2026-09-01T09:00:00+00:00",
"_modified_at": "2026-09-15T14:30:00+00:00"
}Rules:
- Names are unique per project, ignoring case.
- A project can have up to 50 agent keys.
- Updating
collectionsorpermissionsreplaces the whole list; it does not merge. - Rotating a key issues a new secret. The old key stops working right away.
- Rotation preserves
expires_at. - Disabled, rotated, and deleted keys return
404 PROJECT_NOT_FOUND. - Expired keys return
401 AGENT_KEY_EXPIREDbefore scope checks and usage tracking.
Expiry and extension
Create and update accept expires_at, an absolute ISO 8601 time with Z or a timezone offset. The stored value is returned in UTC with Z. null means never expires, and is the default for new keys. Older keys without this field continue to work without expiry.
The timestamp must be in the future, allowing up to one minute of clock skew at save time. Naive or older timestamps return 400 INVALID_EXPIRY; invalid syntax returns INVALID_PAYLOAD. Authentication rejects at the exact expiry time.
Use console.update_agent_key { id, expires_at } to extend an expired key. The same secret works immediately afterward. Omitting the field keeps its current value; sending null removes the expiry. Expiration does not delete the key.
Example: Tool for an LLM Agent
Expose Singlebase to a tool-calling model with one generic tool. The agent key's permissions remain the real security boundary.
Tool definition:
json
{
"name": "singlebase",
"description": "Call the Singlebase backend API. Use operation names such as data.query, data.insert, files.query, llm.summarize. Put all parameters in payload.",
"input_schema": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"description": "Operation name, for example data.query"
},
"payload": {
"type": "object",
"description": "Operation parameters, for example {\"collection\": \"orders\", \"filter\": {\"status\": \"open\"}}"
}
},
"required": ["operation", "payload"]
}
}Tool handler (JavaScript SDK, server-side):
javascript
import { SinglebaseClient, SinglebaseError } from "@singlebase/singlebase-sdk";
const sbc = SinglebaseClient({
baseUrl: process.env.SINGLEBASE_API_URL,
apiKey: process.env.SINGLEBASE_AGENT_KEY,
});
async function singlebase(operation, payload) {
try {
const data = await sbc.dispatch({ operation, payload }, { bearer: null });
return { data };
} catch (error) {
if (error instanceof SinglebaseError) {
return { error: error.code, status: error.status };
}
throw error;
}
}The JavaScript SDK returns data directly and throws API errors. Keep this agent handler on your server. See JavaScript SDK for connection options.
Example calls the agent might make:
json
{ "operation": "data.query", "payload": { "collection": "orders", "filter": { "status": "open" }, "per_page": 5 } }json
{ "operation": "data.insert", "payload": { "collection": "support_notes", "data": { "order_id": "ord_123", "note": "Customer asked for a refund." } } }json
{ "operation": "llm.summarize", "payload": { "content": "<ticket thread>", "input": "Three bullets." } }Quick Reference for AI Agents
A compact summary of the API for models that read these docs.
Request: POST <API_URL>, headers Content-Type: application/json and X-API-KEY: <key>, body {"operation": "<namespace.action>", "payload": {...}}.
Success: {"data": ..., "meta": {...}}. Error: {"error": {"type", "status", "message"}}; message is a stable code.
Common operations:
| Goal | Operation | Minimal payload |
|---|---|---|
| Find documents | data.query | {"collection": "c", "filter": {...}} |
| Get one document | data.query | {"collection": "c", "filter": {"_id": "id"}, "limit": 1} |
| Search by keyword | data.query | {"collection": "c", "search": "words"} |
| Count | data.count | {"collection": "c", "filter": {...}} |
| Totals | data.aggregate | {"collection": "c", "compute": {"n": {"$count": "*"}}} |
| Create | data.insert | {"collection": "c", "data": {...}} |
| Patch by ID | data.update | {"collection": "c", "data": {"_id": "id", "field": "value"}} |
| Create or update | data.upsert | {"collection": "c", "filter": {...}, "insert_data": {...}, "update_data": {...}} |
| Delete | data.delete | {"collection": "c", "id": "id"} |
| List files | files.query | {"per_page": 20} |
| File download URL | files.get_signed_url | {"id": "file_id"} |
| Summarize text | llm.summarize | {"content": "..."} |
| Extract JSON | llm.extract | {"content": "...", "format": "json"} |
| Search by meaning | chat.ask | {"message": "...", "mode": "kb", "retrieval": [{"source": "docset", "ids": "slug"}]} |
| Find a user | users.query | {"search": "email or name"} |
Syntax reminders:
- Filters:
{"field": value},{"field:$gte": 10},{"$or": [{...}, {...}]}. See Query Syntax. - Update operators:
"count:$incr": 1,"tags:$push": "x","old:$unset": true. See Data Operators. - Templates:
"{{ field }}"(string),"&:{{ a * b }}"(native),"{{ $now() }}"(helper). See Templates.
Error handling:
| Message | What the agent should do |
|---|---|
AGENT_SCOPE_DENIED | Stop. The key lacks permission; don't retry |
INVALID_PAYLOAD | Check details, fix the payload, retry once |
MISSING_COLLECTION_NAME | Add payload.collection |
HTTP 429 | Wait with exponential backoff, then retry |
HTTP 5xx | Retry later with backoff |
Best Practices
- Least privilege - Start with
readon one collection and add permissions as needed. - One key per agent - Separate keys make usage, auditing, and revocation simple.
- Keep keys server-side - Store agent keys in environment variables or a secret manager, never in prompts, client code, or logs.
- Use docsets for knowledge - Give agents curated docsets with
acl: "agent"instead of broad collection access. - Rotate regularly - Rotate keys on a schedule and right away if one leaks.
- Return errors to the model - Error codes are stable, so agents can recover from
INVALID_PAYLOADon their own.
Next Steps
- Data - Operations available to collection permissions
- LLM - Generation, answers, and embeddings
- Conversation - Chats, docsets, and attachments
- Files - Upload and serve files
- Users - Admin user management