Developer docs

Build on MonkeyDB.

MonkeyHUB is now one focused API: a serverless, org-scoped database for AI agents running at api.monkeyhub.ai.

api.monkeyhub.ai
Base URL
10k ops
Free tier
5 per collection
Indexes
quickstart.ts
import { MonkeyHubClient } from "@monkeyhub/sdk";

const monkey = new MonkeyHubClient({
  apiKey: process.env.MONKEYHUB_API_KEY!
});

const memories = monkey.db("app").collection({
  name: "memories",
  key: ["agentId", "memoryId"],
  indexes: [{ field: "status", sort: "createdAt" }]
});

await memories.save({
  agentId: "agent_7",
  memoryId: "memory_1",
  status: "active",
  createdAt: new Date().toISOString()
});
Quickstart

Declare a collection, then save records.

Collections use your own field names. Ensure explicitly, include a schema on the first save, or let a record with an id field create an id-keyed collection.

Ensure collection
PUT /v1/app/memories
{
  "key": "agentId",
  "sort": "memoryId",
  "indexes": [
    { "field": "status", "sort": "createdAt" }
  ]
}
Save record
PUT /v1/app/memories/agent_7/memory_1
{
  "data": {
    "agentId": "agent_7",
    "memoryId": "memory_1",
    "status": "active",
    "createdAt": "2026-04-22T12:00:00Z"
  },
  "ttl": 1798761600
}
Authentication

Use bearer API keys.

Product calls authenticate with Authorization: Bearer mk_live_.... Human and agent keys resolve to an org-scoped request context; storage operations derive the organization from that context rather than request data.

Who am I
curl https://api.monkeyhub.ai/whoami \
  -H "Authorization: Bearer mk_live_..."
Schema

Collection keys are stable; indexes are additive.

Key, sort, and index declarations use top-level record fields. Repeating an ensure is safe, and new indexes can be added without changing existing mappings.

Key
agentId
Sort
memoryId (optional)
Indexes
status + createdAt
Records

Every record is org-scoped.

REST keeps user data in data and server metadata beside it. TTL accepts ISO-8601 or epoch seconds. Save and patch can send ifUpdatedAt to reject stale writes; patch treats null as field deletion. The SDK and MCP flatten the response envelope.

Record shape
{
  "data": {
    "agentId": "agent_7",
    "memoryId": "memory_1",
    "status": "active"
  },
  "updatedAt": 1776859200000,
  "ttl": 1798761600
}
Query

Query with your record's field names.

Range operators are eq, lt, lte, gt, gte, between, and beginsWith.

Primary key

Select a key value and optionally narrow its declared sort field.

{ "where": { "agentId": "agent_7", "memoryId": { "beginsWith": "memory_" } } }

Newest records

Omit where to read the collection's most recently updated records.

{ "limit": 50 }

Declared index

Use the record fields you declared; storage mappings stay private.

{ "where": { "status": "active", "createdAt": { "gte": "2026-04-01" } } }
Recovery

Verified, portable, self-serve backups.

Every active collection is snapshotted nightly, and you can snapshot one collection or an entire database before risky work. Manifests carry the collection schema, record count, compressed byte count, and SHA-256 checksum.

Nominal RPO
24 h nightly · minutes on demand
Nominal RTO
Minutes for self-serve restore
Format
gzip JSONL · public record envelopes

Downloads use 15-minute presigned URLs. Restore verifies bytes, checksum, and record count, creates a new collection from the embedded schema, preserves every original updatedAt, and verifies the written count. Synchronous restore supports up to 50,000 records; larger snapshots use download plus chunked batch import.

TypeScript backup workflow
const database = monkey.db("app");
const snapshots = await database.snapshot("memories");
const snapshot = snapshots[0];
if (!snapshot) throw new Error("No active collection to snapshot");
const download = await database.downloadBackup("memories", snapshot.snapshot);
const restored = await database.restore({
  collection: "memories",
  snapshot: snapshot.snapshot,
  target: "memories_verified"
});
REST

Endpoint reference.

MethodPathPurposeNotes
GET/v1List databasesReturns databases visible to the current key.
PUT/v1/:dbConfigure databaseCreates or updates environment, description, and deletion protection.
DELETE/v1/:dbDelete databaseCascade soft-deletes active collections; blocked by deletion protection.
PUT/v1/:db/:collectionEnsure collectionCreates a collection or adds indexes idempotently.
GET/v1/:dbList collectionsReturns active collection metadata for a database.
GET/v1/:db/:collectionGet collectionReturns schema, status, and recovery metadata.
DELETE/v1/:db/:collectionDelete collectionSoft-deletes a collection for 7-day recovery.
POST/v1/:db/:collection/restoreRestore collectionRestores during the recovery window.
PUT/v1/:db/:collection/:key[/:sort]Save recordThe path must match the schema-named data fields.
PATCH/v1/:db/:collection/:key[/:sort]Patch recordUpdates selected fields; null removes a field; ifUpdatedAt rejects stale writes.
GET/v1/:db/:collection/:key[/:sort]Get recordReads by the collection key and optional sort value.
DELETE/v1/:db/:collection/:key[/:sort]Delete recordDeletes by the same uniform record path.
POST/v1/:db/:collection/queryQuery recordsUses declared field names; empty where returns newest first.
POST/v1/:db/:collection/batchBatch writeTransactional save/delete, max 25 operations.
GET/v1/:db/_backupsList backupsReturns verified manifest entries.
GET/v1/:db/_backups/downloadDownload backupReturns a 15-minute presigned gzip JSONL URL.
POST/v1/:db/_backupsSnapshot nowSnapshots one collection or the active database.
POST/v1/:db/_backups/restoreRestore backupCreates a new collection and preserves updatedAt.
Agents

Use REST, MCP, or the TypeScript SDK.

Agents can connect to https://api.monkeyhub.ai/mcp. Generated SKILL.md and openapi.json are served from the same host, and @monkeyhub/sdk wraps the DB client surface.

TypeScript SDK
import { MonkeyHubClient } from "@monkeyhub/sdk";

const monkey = new MonkeyHubClient({ apiKey });
const database = monkey.db("app");
const memories = database.collection({
  name: "memories",
  key: ["agentId", "memoryId"],
  indexes: [{ field: "status" }]
});

await memories.save({
  agentId: "agent_7",
  memoryId: "memory_1",
  status: "active"
});

const result = await memories.query({
  status: "active"
}, { limit: 50 });
Limits

Operational rules.

Database and collection names
[a-z0-9_-]{1,64}; names starting with _ are reserved
Indexes
5 per collection; declarations are additive
Record size
400 KB including storage attributes
Batch size
25 save/delete operations
Free plan
10,000 MonkeyDB operations per month
Paid plans
Pro: 1,000,000 ops; Ultra: 25,000,000 ops
Backups
Nightly + on demand; 5 snapshots and 5 restores per rolling 24 h per database