Documentation

Build with PerceptDB

The live multimodal data cloud. Store objects, embeddings, events, and metadata — query with SQL, API, CLI, or natural language.

Quickstart

A complete pipeline — here, from an RTSP camera — to natural-language search. The same flow works for logs, sensors, audio, and any other stream.

1Create your workspace

Sign up at perceptdb.com, pick a plan, and grab an API key from Settings → API keys.

export PERCEPT_KEY="pk_live_…"   # Settings → API keys
2Connect a stream

In the console: Streams → New stream → paste an RTSP/HLS URL (cameras) — capture and perception start automatically. For logs, sensors, or events, push JSON with the stream's ingest token:

curl -X POST https://perceptdb.com/api/v1/streams/{streamId}/events \
  -H "Authorization: Bearer pk_strm_…" \
  -H "Content-Type: application/json" \
  -d '{"body": "FATAL: connection pool exhausted", "payload": {"service": "api"}}'
3Or upload files directly
curl -X POST https://perceptdb.com/api/v1/objects \
  -H "Authorization: Bearer $PERCEPT_KEY" \
  -d '{"filename": "dock-cam.mp4", "mimeType": "video/mp4", "sizeBytes": 1234567}'
# → PUT your bytes to the returned uploadUrl, then:
curl -X POST https://perceptdb.com/api/v1/objects/{objectId}/complete \
  -H "Authorization: Bearer $PERCEPT_KEY"
4Search in plain English
curl -X POST https://perceptdb.com/api/v1/search \
  -H "Authorization: Bearer $PERCEPT_KEY" \
  -d '{"query": "person carrying a package near the entrance"}'
5Add an alert

Console → Alerts → New alert. Pick a ready-made preset (after-hours person, error in logs, sensor over limit…) or describe a custom watch in plain English — matches notify you by bell + Discord.

Core concepts

Five primitives. Everything is built from these.

Object
A file or media asset — image, video, PDF, audio, document, blob
Record
A structured row — camera, delivery, customer, shipment, claim
Embedding
A vector representation — image, text, video segment, audio, multimodal
Event
A timestamped meaningful occurrence — package delivered, door opened, signature detected
Trace
The provenance chain — raw object → segment → embedding → event → query result → evidence

SDKs

Official Python and TypeScript SDKs are in development. The REST API is a plain JSON interface, so any HTTP client works today:

Python (requests)

import requests

r = requests.post(
    "https://perceptdb.com/api/v1/search",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"query": "person carrying a package near the entrance"},
)
hits = r.json()["hits"]

TypeScript (fetch)

const r = await fetch("https://perceptdb.com/api/v1/search", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PERCEPT_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ query: "person in a red hoodie at the loading dock" }),
});
const { hits } = await r.json();

Percept SQL

Postgres-compatible plus multimodal functions.

Semantic + metadata hybrid query

SELECT object, stream, caption, capture_ts,
  SEMANTIC_SCORE('person carrying cardboard box') AS score
FROM frame_captions
WHERE stream ILIKE '%dock%'
  AND capture_ts > NOW() - INTERVAL '24 hours'
ORDER BY score DESC NULLS LAST
LIMIT 20;

Time-window event query

SELECT s.name AS stream, e.event_type, e.count, e.created_at
FROM object_events e
JOIN streams s ON s.id = e.stream_id
WHERE e.event_type = 'person_present'
  AND (e.created_at AT TIME ZONE 'America/Los_Angeles')
      > (NOW() AT TIME ZONE 'America/Los_Angeles')::date
ORDER BY e.created_at DESC;

What you can query

SEMANTIC_SCORE
Encrypted vector similarity as a float column
frame_captions
Per-chunk scene readings + transcripts
object_events
Derived events (person_present, loitering…)
detections
Bounding boxes, when a detector runs
stream_events
Raw ingested records (body + payload JSON)
objects / streams
Your media + sources

REST API

Base URL: https://perceptdb.com/api/v1 · auth via Authorization: Bearer <api key>

POST/v1/searchSemantic search across text + video frames
POST/v1/sqlRead-only SQL over your project views (SEMANTIC_SCORE supported)
GET/v1/objectsList objects
POST/v1/objectsStart an upload (returns a presigned PUT URL)
POST/v1/objects/{id}/completeFinish an upload — perception runs automatically
GET/v1/objects/{id}Object metadata + download URL
GET/v1/eventsQuery derived perception events
GET/v1/indexesVector index stats
POST/v1/streams/{id}/eventsPush events to a stream (per-stream ingest token)
POST/v1/streams/{id}/webhookWebhook ingest (Slack, GitHub, custom)

Vectors (bring your own embeddings)

Use PerceptDB as an encrypted vector + metadata store: create an index with a fixed dimension, then read and write raw vectors with documents and metadata attached.

POST/v1/indexesCreate a vector index ({ name, dim, metric? })
DELETE/v1/indexes/{name}Delete an index and its vectors
POST/v1/vectors/{index}Upsert vectors ({ items: [{ id, vector, document?, metadata? }] })
POST/v1/vectors/{index}/queryNearest-neighbor search ({ vector | vectors, topK?, where? })
POST/v1/vectors/{index}/getFetch by ids or metadata filter ({ ids? | where?, offset?, limit? })
POST/v1/vectors/{index}/updateReplace metadata for existing ids ({ ids, metadatas })
POST/v1/vectors/{index}/deleteDelete by ids or metadata filter ({ ids? | where? })
GET/v1/vectors/{index}/countVector count for an index

Create an index once (its dimension is fixed), then upsert your own embeddings with documents and metadata, and query with metadata filters. Index names are lowercase [a-z0-9_-]; each is its own encrypted store.

# 1. create an index (768-dim, cosine)
curl -X POST https://perceptdb.com/api/v1/indexes \
  -H "Authorization: Bearer $PERCEPT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"name":"documents","dim":768,"metric":"cosine"}'

# 2. upsert vectors you embedded yourself (up to 512 per request)
curl -X POST https://perceptdb.com/api/v1/vectors/documents \
  -H "Authorization: Bearer $PERCEPT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"items":[
        {"id":"doc-1","vector":[0.01, -0.02, ...],
         "document":"quarterly report intro",
         "metadata":{"project":"acme","admin_id":"u1"}}
      ]}'

# 3. nearest-neighbor query with a metadata filter
curl -X POST https://perceptdb.com/api/v1/vectors/documents/query \
  -H "Authorization: Bearer $PERCEPT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"vector":[0.01, -0.02, ...], "topK":10,
       "where":{"project":{"$eq":"acme"}}}'

Filters accept $eq $ne $in $nin $lt $lte $gt $gte and $and $or. Vectors are stored encrypted; the same rows are visible in SQL via api.embeddings.

CLI

A percept CLI is in development. Until it ships, everything is available through the console and the REST API above — the API examples in the Quickstart cover the same flows (upload, ingest, search, SQL).

Security & governance

Encryption at rest
AES-256 · vectors encrypted (CyborgDB)
Encryption in transit
TLS 1.3 everywhere
RBAC
Org → Project → Resource scopes
Audit logs
Org-wide action trail
Tenant isolation
Enforced at the database layer
Compliance
Security review available · certifications on the roadmap