Skip to main content
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)

The API starts at 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:
  1. Control plane (app_* tables via Drizzle ORM) — orgs, projects, API keys, usage metrics
  2. Provenance storage (pk_* tables via Supabase JS SDK + pgvector) — EAA records, embeddings
Both can live in the same PostgreSQL/Supabase database.
  1. Create a project at supabase.com
  2. Copy Project URL and service_role key from Settings → API
  3. Set SUPABASE_URL and SUPABASE_SERVICE_KEY
  4. Set DATABASE_URL to the pooler connection string (Settings → Database → Connection pooling)
  5. Run migrations: pnpm --filter provenancekit-api db:push
Enable pgvector in Supabase SQL Editor:

PostgreSQL Direct

Set DATABASE_URL to a direct PostgreSQL connection string. Run:
This syncs the Drizzle schema to your database.

Production Deployment

Docker

Railway / Render / Fly.io

Set the build command to:
Start command:
Set all environment variables in the platform’s UI.

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: Management key is a single shared secret. Provenance keys are scoped to a project, stored as SHA-256 hashes in app_api_keys.

Rate Limiting

The API includes in-memory sliding-window rate limiting on all /v1/* routes:
Response headers:
When exceeded, the API returns 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 with CREATE 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_URL is not set, the API uses in-memory storage. All data is lost on restart. Only use this for local testing.