Run provenancekit-api on your own infrastructure. All features (Supabase storage, IPFS, blockchain anchoring) work exactly the same as the hosted version at api.provenancekit.com.
Prerequisites
- Node.js 20+ and pnpm
- PostgreSQL database (Supabase recommended) or in-memory mode for development
- Pinata account for IPFS file storage (optional — in-memory for local dev)
- An EVM wallet for blockchain recording (optional)
Quick Start (Local Development)
http://localhost:3001. In-memory mode works out of the box with no external services required.
Environment Variables
Database Setup
ProvenanceKit uses two data layers:- Control plane (
app_*tables via Drizzle ORM) — orgs, projects, API keys, usage metrics - Provenance storage (
pk_*tables via Supabase JS SDK + pgvector) — EAA records, embeddings
Supabase (Recommended)
- Create a project at supabase.com
- Copy Project URL and service_role key from Settings → API
- Set
SUPABASE_URLandSUPABASE_SERVICE_KEY - Set
DATABASE_URLto the pooler connection string (Settings → Database → Connection pooling) - Run migrations:
pnpm --filter provenancekit-api db:push
pgvector in Supabase SQL Editor:
PostgreSQL Direct
SetDATABASE_URL to a direct PostgreSQL connection string. Run:
Production Deployment
Docker
Railway / Render / Fly.io
Set the build command to:Pointing the Dashboard at Your API
In the ProvenanceKit dashboard → Project → Settings → Self-hosted API, set your API URL. The dashboard will use your instance for all provenance operations for that project. Or set it via the SDK:API Key Management
There are two types of API keys:| Type | Format | Purpose |
|---|---|---|
| Management key | mk_live_... | Dashboard → API server-to-server (set in MANAGEMENT_API_KEY) |
| Provenance key | pk_live_... | Developer apps → Provenance API (managed via dashboard or direct DB) |
app_api_keys.
Rate Limiting
The API includes in-memory sliding-window rate limiting on all/v1/* routes:
429 TooManyRequests with a Retry-After header.
Health Check
Gotchas
- DATABASE_URL pooler vs direct: For Drizzle/migrations use the direct connection. For the app at runtime, the pooler is fine (and required for serverless).
- pgvector: Must be enabled in your Postgres instance before running
db:push. On Supabase, enable it via the Dashboard → Extensions or withCREATE EXTENSION vector. - MANAGEMENT_API_KEY: Never expose this to the browser. It’s used only for server-to-server calls between the dashboard app and the API.
- Blockchain private key: The server wallet must have ETH on the target chain. Monitor the balance; on-chain recording is fire-and-forget and won’t crash the API if it fails.
- In-memory mode: When
SUPABASE_URLis not set, the API uses in-memory storage. All data is lost on restart. Only use this for local testing.