npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

paygate-mcp

v9.2.0

Published

Pay-per-tool-call gating proxy for MCP servers. Wrap any MCP server with API key auth, per-tool pricing, rate limiting, and usage metering.

Readme

paygate-mcp

CI npm version License: MIT

Monetize any MCP server with one command. Add API key auth, per-tool pricing, rate limiting, and usage metering to any Model Context Protocol server. Zero dependencies. Zero config. Zero code changes.

Table of Contents

Quick Start

# Wrap a local MCP server (stdio transport)
npx paygate-mcp wrap --server "npx @modelcontextprotocol/server-filesystem /tmp"

# Gate a remote MCP server (Streamable HTTP transport)
npx paygate-mcp wrap --remote-url "https://my-server.example.com/mcp" --price 5

That's it. Your MCP server is now gated behind API keys with credit-based billing.

What It Does

PayGate sits between AI agents and your MCP server:

Agent → PayGate (auth + billing) → Your MCP Server (stdio or HTTP)
  • API Key Auth — Clients need a valid X-API-Key to call tools
  • Credit Billing — Each tool call costs credits (configurable per-tool)
  • Rate Limiting — Sliding window per-key rate limits + per-tool rate limits
  • Usage Metering — Track who called what, when, and how much they spent
  • Multi-Server Mode — Wrap N MCP servers behind one PayGate with tool prefix routing
  • Client SDKPayGateClient with auto 402 retry, balance tracking, and typed errors
  • Two Transports — Wrap local servers via stdio or remote servers via Streamable HTTP
  • Per-Tool ACL — Whitelist/blacklist tools per API key (enterprise access control)
  • Per-Tool Rate Limits — Independent rate limits per tool, not just global
  • Key Expiry (TTL) — Auto-expire API keys after a set time
  • Spending Limits — Cap total spend per API key to prevent runaway costs
  • Usage Quotas — Daily/monthly call and credit limits per key (with UTC auto-reset)
  • Dynamic Pricing — Charge extra credits based on input size (creditsPerKbInput)
  • OAuth 2.1 — Full authorization server with PKCE, client registration, Bearer tokens
  • SSE Streaming — Full MCP Streamable HTTP transport (POST SSE, GET notifications, DELETE sessions)
  • Audit Log — Structured audit trail with retention policies, query API, CSV/JSON export
  • Registry/Discovery — Agent-discoverable pricing via /.well-known/mcp-payment, /pricing, and /.well-known/mcp.json identity card
  • OpenAPI 3.1 + Interactive Docs — Auto-generated spec at /openapi.json, Swagger UI at /docs — all 140+ endpoints documented
  • Public Endpoint Rate Limiting — Configurable per-IP rate limit (default 300/min) on /health, /info, /pricing, /docs, /openapi.json, /.well-known/*, /robots.txt, / — 429 with Retry-After header
  • Robots.txt + HEAD Support — Standard /robots.txt (allow public, disallow admin/keys), HEAD method on all public endpoints for uptime monitoring
  • Prometheus Metrics/metrics endpoint with counters, gauges, and uptime in standard text format
  • Key Rotation — Rotate API keys without losing credits, ACLs, or quotas
  • Rate Limit HeadersX-RateLimit-* and X-Credits-Remaining on every /mcp response
  • Webhook Signatures — HMAC-SHA256 signed webhook payloads (X-PayGate-Signature) for tamper-proof delivery
  • Admin Lifecycle Events — Webhook notifications for key.created, key.revoked, key.rotated, key.topup
  • IP Allowlisting — Restrict API keys to specific IPs or CIDR ranges (IPv4)
  • Key Tags/Metadata — Attach arbitrary key-value tags to API keys for external system integration
  • Usage Analytics — Time-series analytics API with tool breakdown, top consumers, and trend comparison
  • Alert Webhooks — Configurable alerts for spending thresholds, low credits, quota warnings, key expiry, rate limit spikes
  • Team Management — Group API keys into teams with shared budgets, quotas, and usage tracking
  • Horizontal Scaling (Redis) — Redis-backed state for multi-process deployments with atomic credit deduction, distributed rate limiting, persistent usage audit trail, real-time pub/sub notifications, and admin API sync
  • Webhook Retry Queue — Exponential backoff retry (1s, 2s, 4s...) with dead letter queue for permanently failed deliveries, admin API for monitoring, clearing, and replaying
  • Admin Dashboard v2 — Tabbed web dashboard at /dashboard with overview, keys management (create/suspend/resume/revoke/top-up), analytics (credit flow, deny reasons, top consumers, webhook health), and system status — all data via safe DOM methods, 30s auto-refresh
  • Self-Service Portal — API key holder portal at /portal — check credits, usage, rate limits, available tools, and recent activity without admin access; includes Buy Credits UI, credit history with spending velocity, usage alerts, and self-service key rotation
  • Stripe Checkout — Self-service credit purchases via Stripe Checkout Sessions — POST /stripe/checkout creates a session, GET /stripe/packages lists available packages; zero-dependency implementation using Node.js https, auto-tops-up credits via webhook
  • State Backup & RestoreGET /admin/backup exports full server state (keys, teams, groups, webhooks) as versioned JSON with SHA-256 checksum; POST /admin/restore imports with merge/overwrite/full modes and integrity verification
  • API Version HeaderX-PayGate-Version header on every HTTP response for client version tracking, exposed via CORS
  • Readiness ProbeGET /ready returns 200/503 based on operational state (not draining, not maintenance, backend connected) — separate from /health liveness probe, ideal for Kubernetes
  • Health Check + Graceful ShutdownGET /health public endpoint with status, uptime, version, in-flight requests, Redis & webhook stats; gracefulStop() drains in-flight requests before teardown
  • Config Validation + Dry Runpaygate-mcp validate --config paygate.json catches misconfigurations before starting; --dry-run discovers tools, prints pricing table, then exits
  • Batch Tool Callstools/call_batch method for calling multiple tools in one request with all-or-nothing billing, aggregate credit checks, and parallel execution
  • Multi-Tenant Namespaces — Isolate API keys and usage data by tenant with namespace-filtered admin endpoints, analytics, and usage export
  • Scoped Tokens — Issue short-lived pgt_ tokens scoped to specific tools with auto-expiry (max 24h), HMAC-SHA256 signed, zero server-side state
  • Token Revocation List — Revoke scoped tokens before expiry with O(1) lookup, auto-cleanup, Redis cross-instance sync, and admin API
  • Usage-Based Auto-Topup — Automatically add credits when balance drops below a threshold with configurable daily limits, audit trail, webhook events, and Redis sync
  • Admin API Key Management — Multiple admin keys with role-based permissions (super_admin, admin, viewer), file persistence, audit trail, and safety guards
  • Plugin System — Extensible middleware hooks for custom billing logic, request/response transformation, custom endpoints, and lifecycle management
  • Key Groups — Policy templates that apply shared ACL, rate limits, pricing overrides, IP allowlists, and quotas to groups of API keys with automatic inheritance and key-level override support
  • Refund on Failure — Automatically refund credits when downstream tool calls fail
  • Credit Transfers — Atomically transfer credits between API keys with validation, audit trail, and webhook events
  • Bulk Key Operations — Execute multiple key operations (create, topup, revoke) in a single request with per-operation error handling and index tracking
  • Key Import/Export — Export all API keys for backup/migration (JSON or CSV) and import with conflict resolution (skip, overwrite, error modes)
  • Webhook Filters — Route webhook events to different destinations based on event type and API key prefix with per-filter secrets, independent retry queues, and admin CRUD API
  • Key CloningPOST /keys/clone creates a new API key with the same config (ACL, quotas, tags, IP, namespace, group, spending limit, expiry, auto-topup) but fresh counters — ideal for provisioning similar keys
  • Key Suspension — Temporarily disable API keys without revoking them — suspended keys are denied at the gate but can be resumed, and admin operations (topup, ACL, etc.) still work on suspended keys
  • Per-Key UsageGET /keys/usage?key=... returns detailed usage breakdown for a specific key: per-tool stats, hourly time-series, deny reasons, recent events, and key metadata
  • Webhook TestPOST /webhooks/test sends a test event to your configured webhook URL with synchronous response including status code, response time, and delivery success/failure — verifies webhook connectivity without generating real events
  • Webhook Delivery LogGET /webhooks/log returns a queryable log of all webhook delivery attempts with timestamps, HTTP status codes, response times, success/failure, retry attempts, event counts, and event types — filter by success status, time range, and limit
  • Webhook Pause/ResumePOST /webhooks/pause and POST /webhooks/resume temporarily halt webhook delivery during maintenance — events are buffered (not lost) and flushed on resume, with pause state visible in /webhooks/stats
  • Key AliasesPOST /keys/alias assigns human-readable aliases (e.g. my-service, prod-backend) to API keys — use aliases in any admin endpoint (topup, revoke, suspend, resume, clone, transfer, usage) instead of opaque key IDs, with uniqueness enforcement, format validation, state file persistence, and audit trail
  • Key Expiry Scanner — Proactive background scanner that detects expiring API keys before they expire — configurable scan interval and notification thresholds (default: 7d, 24h, 1h), de-duplicated key.expiry_warning webhook events, audit trail, GET /keys/expiring?within=86400 query endpoint, and graceful shutdown
  • Key Templates — Named templates for API key creation — define reusable presets (credits, ACL, quotas, IP, tags, namespace, expiry TTL, spending limit, auto-topup) and create keys with template: "free-tier" — explicit params override template defaults, CRUD admin API, Prometheus gauge, file persistence, max 100 templates
  • Environment Variables Config — Configure everything via PAYGATE_* env vars for Docker/K8s deployments — 18 env vars covering all CLI flags, with priority: CLI flags > env vars > config file > defaults, PAYGATE_CONFIG loads config file path, help text with Docker examples
  • Request ID Tracking — Every HTTP response includes X-Request-Id header (auto-generated req_ prefix + 16 hex chars) for distributed tracing — propagates incoming X-Request-Id from load balancers/proxies, included in gate audit log metadata, CORS-exposed, available via getRequestId(req) helper
  • Server Info EndpointGET /info returns server capabilities, enabled features, auth methods, pricing summary, rate limits, and available endpoints — public, no admin key required, ideal for agent auto-discovery and debugging
  • Configurable CORS — Control which origins can access your server: single origin, multiple origins, or wildcard (* default), with credentials support, configurable preflight max-age, and Vary: Origin for proper caching — set via config file cors object, --cors-origin CLI flag, or PAYGATE_CORS_ORIGIN env var
  • Custom Response Headers — Add security headers (X-Frame-Options, X-Content-Type-Options, etc.), cache control, or any custom headers to all HTTP responses — set via config file customHeaders object, --header CLI flag, or PAYGATE_CUSTOM_HEADERS env var
  • Config ExportGET /config returns the running server configuration with sensitive values masked (webhook secrets → ***, server commands → ***, webhook URLs → scheme+host only) — admin auth required, includes audit trail
  • Trusted Proxies — Configure trusted proxy IPs/CIDRs for accurate X-Forwarded-For extraction — walks the header right-to-left, skipping trusted proxies to find the real client IP, supports exact IPs and CIDR ranges (IPv4), backward compatible (first IP) when not configured
  • Key Listing Pagination — Enhanced GET /keys with cursor-based pagination (limit/offset), sorting (sortBy/order), and filtering by namespace, group, active/suspended/expired status, name prefix, and credit range — backward compatible (returns flat array when no pagination params used)
  • Key StatisticsGET /keys/stats returns aggregate statistics across all keys — total/active/suspended/expired/revoked counts, credit aggregates (allocated/spent/remaining), total calls, namespace and group breakdowns, optional ?namespace= filter
  • Rate Limit StatusGET /keys/rate-limit-status?key=... returns the current rate limit window state for any key — global calls used/remaining/reset time, per-tool rate limits with individual usage, read-only (doesn't consume a call)
  • Quota StatusGET /keys/quota-status?key=... returns daily/monthly quota usage for any key — calls and credits used/remaining/limits, reset periods, quota source (per-key vs global vs none)
  • Credit HistoryGET /keys/credit-history?key=... returns per-key credit mutation log — tracks initial allocation, topups, transfers (in/out), auto-topups, with type/limit/since filters, balance-before/after on every entry, newest-first ordering, capped at 100 entries per key
  • Spending VelocityGET /keys/spending-velocity?key=... returns credit burn rate and depletion forecast — credits/calls per hour/day, estimated depletion date, top tools by spend, configurable analysis window (1h–30d)
  • Key ComparisonGET /keys/compare?keys=pg_a,pg_b returns side-by-side comparison of 2–10 keys — credits, usage, velocity, rate limits, status, metadata (namespace/group/tags) — with not-found key reporting
  • Key Health ScoreGET /keys/health?key=... returns composite health score (0–100) with weighted component breakdown: balance health (30%), quota utilization (25%), rate limit pressure (20%), error rate (25%) — status levels (healthy/good/caution/warning/critical), key issue detection (revoked/suspended/expired/expiring/zero credits), alias support
  • Maintenance ModePOST /maintenance enables/disables maintenance mode with custom message — /mcp returns 503 to clients while admin endpoints stay operational, GET /maintenance checks status, GET /health reflects maintenance state, full audit trail
  • Admin Event StreamGET /admin/events SSE endpoint streams real-time audit events to admin clients — tool calls, denials, key operations, maintenance changes, all with optional ?types= filter for event type filtering, keepalive pings, multi-client support
  • Key NotesPOST /keys/notes adds timestamped notes to API keys, GET /keys/notes?key=... lists notes, DELETE /keys/notes?key=...&index=N removes notes — max 50 per key, 1000 char limit, works on suspended/revoked keys, alias support, audit trail
  • Scheduled ActionsPOST /keys/schedule creates future-dated actions (revoke/suspend/topup) on API keys, GET /keys/schedule lists pending schedules with optional ?key= filter, DELETE /keys/schedule?id=... cancels a schedule — max 20 per key, alias support, background execution timer, audit trail
  • Key Activity TimelineGET /keys/activity?key=... returns a unified chronological feed of audit events and usage events for a specific key — newest first, optional ?since= and ?limit= filters, alias support
  • Credit ReservationsPOST /keys/reserve holds credits, POST /keys/reserve/commit deducts held credits, POST /keys/reserve/release frees the hold, GET /keys/reserve lists active reservations — prevents overcommit, configurable TTL (10s–1h), max 50 per key, auto-expiry, audit trail
  • Request LogGET /requests queryable log of every tool call with timing, credits charged, status (allowed/denied), deny reason, key, and request ID — filter by key/tool/status/since, pagination, summary statistics (totals + avg duration), 5000-entry ring buffer
  • Tool StatsGET /tools/stats per-tool analytics: call counts, success rate, avg/p95 latency, credits consumed, deny reason breakdown, top 10 consumers — optional ?tool= for detailed single-tool view, ?since= filter
  • Request Log ExportGET /requests/export exports the full request log as JSON or CSV with Content-Disposition headers — filter by key/tool/status/since/until, combined time-window queries, no pagination limit
  • Tool Call Dry RunPOST /requests/dry-run simulates a tool call without executing — checks key validity, ACL, rate limits, credits, and spending limits, returns predicted outcome with credits-after calculation and rate limit status
  • Batch Dry RunPOST /requests/dry-run/batch simulates multiple tool calls at once — aggregate credit check, per-tool ACL validation, spending limit, returns per-tool results with total credits required and credits-after
  • Tool AvailabilityGET /tools/available?key=... returns per-key tool availability with pricing, affordability (canAfford), ACL enforcement (accessible/denyReason), and per-tool + global rate limit status
  • Key DashboardGET /keys/dashboard?key=... consolidated single-endpoint view with metadata, balance, health score, spending velocity, rate limits, quotas, usage summary, and recent activity timeline
  • Admin NotificationsGET /admin/notifications scans all keys for actionable issues: expired/expiring keys, zero credits, credit depletion velocity, suspended keys, high error rates, and rate limit pressure — with severity filtering and priority sorting
  • System DashboardGET /admin/dashboard system-wide overview with key counts (active/suspended/revoked/expired), credit summary (allocated/spent/remaining), usage breakdown with deny reasons, top consumers, top tools, notification counts, and uptime
  • Key Lifecycle ReportGET /admin/lifecycle aggregated lifecycle trends with daily creation/revocation/suspension buckets, average key lifetime, and at-risk keys (expiring, expired, zero credits)
  • Cost AnalysisGET /admin/costs cost-centric view with per-tool and per-namespace cost breakdowns, hourly spending trends, top spenders, average cost per call, and namespace filtering
  • Rate Limit AnalysisGET /admin/rate-limits rate limit utilization analysis with per-key and per-tool breakdown, denial trends, most throttled keys, and current window utilization
  • Quota AnalysisGET /admin/quotas quota utilization analysis with per-key daily/monthly usage vs limits, per-tool denial breakdown, most constrained keys, and global/per-key quota source tracking
  • Denial AnalysisGET /admin/denials comprehensive denial breakdown by reason type (insufficient_credits, rate_limited, quota_exceeded, key_suspended, etc.) with per-key and per-tool stats, hourly trends, and most denied keys
  • Traffic AnalysisGET /admin/traffic request volume analysis with tool popularity, hourly volume, top consumers by call count, namespace breakdown, peak hour identification, and success rates
  • Response Caching — SHA-256 keyed response cache for identical tool calls — skips backend invocation and credit deduction on cache hit, LRU eviction, per-tool or global TTL, X-Cache: HIT/MISS header, admin management (GET/DELETE /admin/cache), Prometheus gauge
  • Circuit Breaker — Three-state circuit breaker (closed → open → half_open) for backend failure detection — opens after N consecutive failures, auto-recovers after cooldown, error code -32003, admin management (GET/POST /admin/circuit)
  • Configurable Timeouts — Per-tool and global timeout for tool calls — returns error code -32004 on timeout, per-tool override via toolPricing[tool].timeoutMs, triggers circuit breaker failure recording
  • Security AuditGET /admin/security security posture analysis identifying keys without IP allowlists, quotas, ACL restrictions, spending limits, or expiry dates, flagging high-credit keys, and computing a composite security score
  • Revenue AnalysisGET /admin/revenue revenue metrics with per-tool revenue breakdown, per-key spending, hourly revenue trends, credit flow summary (allocated/spent/remaining), and average revenue per call
  • Key Portfolio HealthGET /admin/key-portfolio portfolio-wide key health with active/inactive/suspended counts, stale keys, expiring-soon keys, age distribution, credit utilization, and namespace breakdown
  • Anomaly DetectionGET /admin/anomalies identifies unusual patterns: keys with high denial rates, rapid credit depletion, low remaining credits, with severity ratings and detailed descriptions
  • Usage ForecastingGET /admin/forecast predicts future credit consumption with per-key depletion estimates, calls remaining, at-risk key identification, system-wide consumption aggregates, and per-tool cost breakdown
  • Compliance ReportGET /admin/compliance generates compliance-ready report with key governance (expiry coverage), access control (ACL/IP/spending limit coverage), audit trail completeness, weighted overall score, and actionable recommendations
  • SLA MonitoringGET /admin/sla tracks service level metrics: success rates, denial breakdowns by reason, per-tool availability and error rates, uptime tracking, sorted by call volume
  • Capacity PlanningGET /admin/capacity system capacity analysis with credit burn rates, utilization percentages, top consumers, per-namespace breakdown, and scaling recommendations
  • Key Dependency MapGET /admin/dependencies tool-to-key relationship map with tool usage popularity, unique key counts per tool, per-key tool lists, and used/unused tool identification
  • Tool Latency AnalysisGET /admin/latency per-tool response time metrics with avg/p95/min/max durations, slowest tools ranking, and per-key latency breakdown
  • Error Rate TrendsGET /admin/error-trends denial rate trends with per-tool error rates, denial reason breakdown, worst-performing tools, and trend direction
  • Credit Flow AnalysisGET /admin/credit-flow credit inflow/outflow analysis with utilization percentage, top spenders, and per-tool spend breakdown
  • Key Age AnalysisGET /admin/key-age key age distribution with oldest/newest keys, age buckets (24h/7d/30d/older), and recently created list
  • Namespace Usage SummaryGET /admin/namespace-usage per-namespace usage metrics with credit allocation, spending, call counts, and cross-namespace comparison
  • Audit SummaryGET /admin/audit-summary audit event analytics with type breakdown, top actors, recent events, and activity summary
  • Group PerformanceGET /admin/group-performance per-group analytics with key counts, credit allocation/spending, call volume, utilization, and policy summary
  • Request Volume TrendsGET /admin/request-trends hourly time-series of request volume, success/failure counts, credit spend, avg duration, and peak hour identification
  • Key Status OverviewGET /admin/key-status key status dashboard with active/suspended/revoked/expired counts and keys needing attention (low credits, near expiry)
  • Webhook HealthGET /admin/webhook-health webhook delivery health overview with success rate, pending retries, dead letter count, pause status, and buffered events
  • Consumer InsightsGET /admin/consumer-insights per-key behavioral analytics with top spenders, most active callers, tool diversity, and spending patterns
  • System Health ScoreGET /admin/system-health composite 0-100 health score with weighted component breakdowns for key health, error rates, and credit utilization
  • Tool AdoptionGET /admin/tool-adoption per-tool adoption metrics with unique consumers, adoption rate, first/last seen timestamps, and usage ranking
  • Credit EfficiencyGET /admin/credit-efficiency credit allocation efficiency with burn efficiency, waste ratio, over-provisioned and under-provisioned key detection
  • Access HeatmapGET /admin/access-heatmap hourly access patterns with tool breakdown, unique consumers, and peak hour identification
  • Key Churn AnalysisGET /admin/key-churn key churn metrics with creation/revocation rates, churn and retention percentages, and never-used key detection
  • Tool CorrelationGET /admin/tool-correlation tool co-occurrence analysis showing which tools are commonly used together by the same consumers
  • Consumer SegmentationGET /admin/consumer-segmentation classifies API key consumers into power/regular/casual/dormant segments with per-segment metrics
  • Credit DistributionGET /admin/credit-distribution histogram of credit balances across active keys with bucket ranges and median calculation
  • Response Time DistributionGET /admin/response-time-distribution histogram of response times with latency buckets and p50/p95/p99 percentiles
  • Consumer Lifetime ValueGET /admin/consumer-lifetime-value per-consumer spend analysis with value tiers, tool diversity, and top spender rankings
  • Tool Revenue RankingGET /admin/tool-revenue ranks tools by total credits consumed with call counts, unique consumers, and percentage breakdown
  • Consumer Retention CohortsGET /admin/consumer-retention groups consumers by creation date with retention rates and avg spend per cohort
  • Error BreakdownGET /admin/error-breakdown categorizes denied requests by reason with counts, percentages, affected consumers, and error rate
  • Credit Utilization RateGET /admin/credit-utilization shows utilization percentage across active keys with utilization bands and over-provisioning detection
  • Namespace RevenueGET /admin/namespace-revenue revenue breakdown by namespace with spend, call counts, key counts, and percentage breakdown
  • Group RevenueGET /admin/group-revenue revenue breakdown by key group with spend, call counts, key counts, and percentage breakdown
  • Peak Usage TimesGET /admin/peak-usage traffic patterns by hour-of-day with request counts, credits, unique consumers, and peak hour identification
  • Consumer ActivityGET /admin/consumer-activity per-consumer activity metrics with calls, spend, credits remaining, last active time, and active/inactive status
  • Tool PopularityGET /admin/tool-popularity tool usage popularity with call counts, credits, unique consumers, percentage, and most popular tool identification
  • Credit Allocation SummaryGET /admin/credit-allocation credit allocation across active keys with tier breakdown (1-100, 101-500, 501+), totals, and average allocation
  • Daily SummaryGET /admin/daily-summary daily rollup of requests, credits spent, new keys, errors, unique consumers and tools for trend analysis
  • Key RankingGET /admin/key-ranking leaderboard of active keys ranked by spend, calls, or credits remaining with configurable sorting
  • Hourly TrafficGET /admin/hourly-traffic granular per-hour request counts with allowed/denied breakdown, credits, consumers, tools, and busiest hour
  • Tool Error RateGET /admin/tool-error-rate per-tool error rates with denied/allowed counts, error percentage, and overall reliability metrics
  • Consumer Spend VelocityGET /admin/consumer-spend-velocity per-consumer spend rate with credits/hour, depletion forecast, and velocity ranking
  • Namespace ActivityGET /admin/namespace-activity per-namespace activity metrics with key counts, spend, calls, credits remaining for multi-tenant visibility
  • Credit Burn RateGET /admin/credit-burn-rate system-wide credit burn rate with credits/hour, utilization percentage, depletion forecast
  • Consumer Risk ScoreGET /admin/consumer-risk-score per-consumer risk scoring based on utilization with risk levels (low/medium/high/critical)
  • Revenue ForecastGET /admin/revenue-forecast projected revenue with hourly/daily/weekly/monthly forecasts capped by remaining credits
  • System OverviewGET /admin/system-overview executive summary with key counts, credit totals, utilization, activity metrics
  • Key Health OverviewGET /admin/key-health-overview holistic per-key health check with utilization, status levels, health distribution
  • Namespace ComparisonGET /admin/namespace-comparison side-by-side namespace comparison with allocation, spend, utilization, leader
  • Consumer GrowthGET /admin/consumer-growth consumer growth metrics with age, spend rate, credits allocated, new consumer count
  • Tool ProfitabilityGET /admin/tool-profitability per-tool profitability analysis with revenue, calls, avg revenue per call, unique callers
  • Credit Waste AnalysisGET /admin/credit-waste per-key credit waste analysis with utilization metrics and waste percentage
  • Group ActivityGET /admin/group-activity per-group activity metrics with key counts, spend, calls, credits remaining for policy-template analytics
  • Config Hot ReloadPOST /config/reload reloads pricing, rate limits, webhooks, quotas, and behavior flags from config file without server restart
  • Webhook Events — POST batched usage events to any URL for external billing/alerting
  • Config File Mode — Load all settings from a JSON file (--config)
  • Shadow Mode — Log everything without enforcing payment (for testing)
  • Persistent Storage — Keys, credits, admin keys, and groups survive restarts with --state-file
  • Zero Dependencies — No external npm packages. Uses only Node.js built-ins.

Usage

Wrap a Local MCP Server (stdio)

# Default: 1 credit per call, 60 calls/min, port 3402
npx paygate-mcp wrap --server "npx @modelcontextprotocol/server-filesystem /tmp"

# Custom pricing and limits
npx paygate-mcp wrap \
  --server "python my-server.py" \
  --price 2 \
  --rate-limit 30 \
  --port 8080

# Per-tool pricing
npx paygate-mcp wrap \
  --server "node server.js" \
  --tool-price "search:1,generate:5,premium_analyze:20"

# Shadow mode (observe without enforcing)
npx paygate-mcp wrap --server "node server.js" --shadow

Gate a Remote MCP Server (Streamable HTTP)

Gate any remote MCP server that supports the Streamable HTTP transport (MCP spec 2025-03-26):

npx paygate-mcp wrap --remote-url "https://my-mcp-server.example.com/mcp"

# With custom pricing
npx paygate-mcp wrap \
  --remote-url "https://api.example.com/mcp" \
  --price 5 \
  --tool-price "gpt4:20,search:2"

The proxy handles:

  • JSON-RPC forwarding via HTTP POST
  • SSE (text/event-stream) response parsing
  • Mcp-Session-Id session management
  • Graceful session cleanup (HTTP DELETE on shutdown)

When started, you'll see your admin key in the console. Save it.

Multi-Server Mode

Wrap multiple MCP servers behind a single PayGate instance. Tools are prefixed with the server name:

npx paygate-mcp wrap --config multi-server.json

Example multi-server.json:

{
  "port": 3402,
  "defaultCreditsPerCall": 1,
  "servers": [
    {
      "prefix": "fs",
      "serverCommand": "npx",
      "serverArgs": ["@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    {
      "prefix": "github",
      "remoteUrl": "https://github-mcp.example.com/mcp"
    }
  ]
}

Tools are exposed with prefixes: fs:read_file, fs:write_file, github:search_repos, etc. Pricing and ACLs work on the prefixed names:

{
  "toolPricing": {
    "github:search_repos": { "creditsPerCall": 5 },
    "fs:read_file": { "creditsPerCall": 1 }
  }
}

Credits are shared across all backends — one API key works for all servers.

Client SDK

Use PayGateClient to call tools from TypeScript/Node.js with auto 402 retry:

import { PayGateClient, PayGateError } from 'paygate-mcp/client';

const client = new PayGateClient({
  url: 'http://localhost:3402',
  apiKey: 'pg_abc123...',
  autoRetry: true,
  onCreditsNeeded: async (info) => {
    // Called when credits run out — add credits and return true to retry
    await topUpCredits(info.creditsRequired);
    return true;
  },
});

const tools = await client.listTools();
const result = await client.callTool('search', { query: 'hello' });
const balance = await client.getBalance();

Features:

  • Auto 402 retry: When a tool call returns payment-required, calls onCreditsNeeded and retries
  • Balance tracking: client.lastKnownBalance tracks credits from getBalance() calls
  • Typed errors: PayGateError with .isPaymentRequired, .isRateLimited, .isExpired helpers
  • Zero dependencies: Uses Node.js built-in http/https

Create API Keys

curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "my-client", "credits": 100}'

Call Tools

curl -X POST http://localhost:3402/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: CLIENT_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "read_file",
      "arguments": {"path": "/tmp/test.txt"}
    }
  }'

Top Up Credits

curl -X POST http://localhost:3402/topup \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "credits": 500}'

Check Balance (Client Self-Service)

curl http://localhost:3402/balance \
  -H "X-API-Key: CLIENT_API_KEY"

Returns credits, total spent, call count, and last used timestamp. Clients can check their own balance without needing admin access.

Export Usage Data (Admin)

# JSON export
curl http://localhost:3402/usage \
  -H "X-Admin-Key: YOUR_ADMIN_KEY"

# CSV export (for spreadsheet/billing import)
curl "http://localhost:3402/usage?format=csv" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY"

# Filter by date
curl "http://localhost:3402/usage?since=2025-01-01T00:00:00Z" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY"

Returns per-call usage events with tool name, credits charged, and timestamps. API keys are masked in output.

Check Status

curl http://localhost:3402/status \
  -H "X-Admin-Key: YOUR_ADMIN_KEY"

Returns active keys, usage stats, per-tool breakdown, and deny reasons.

Admin Dashboard

Open the web dashboard in your browser:

http://localhost:3402/dashboard

A real-time admin UI for managing keys, viewing usage, and monitoring tool calls. Enter your admin key to authenticate. Features auto-refresh every 30s, top tools chart, activity feed, and key creation/management.

API Reference

| Endpoint | Method | Auth | Description | |----------|--------|------|-------------| | /mcp | POST | X-API-Key or Bearer | JSON-RPC 2.0 proxy (returns JSON or SSE) | | /mcp | GET | X-API-Key or Bearer | SSE notification stream (Streamable HTTP) | | /mcp | DELETE | Mcp-Session-Id | Terminate an MCP session | | /balance | GET | X-API-Key | Client self-service — check credits, quota, ACL, expiry | | /keys | POST | X-Admin-Key | Create API key (with ACL, expiry, quota, credits) | | /keys | GET | X-Admin-Key | List all keys (masked, with expiry status) | | /topup | POST | X-Admin-Key | Add credits to an existing key | | /keys/transfer | POST | X-Admin-Key | Transfer credits between API keys | | /keys/bulk | POST | X-Admin-Key | Execute multiple key operations (create, topup, revoke) in one request | | /keys/export | GET | X-Admin-Key | Export all API keys for backup/migration (JSON or CSV) | | /keys/import | POST | X-Admin-Key | Import API keys from backup with conflict resolution | | /keys/revoke | POST | X-Admin-Key | Permanently revoke an API key | | /keys/suspend | POST | X-Admin-Key | Temporarily suspend a key (reversible) | | /keys/resume | POST | X-Admin-Key | Resume a suspended key | | /keys/clone | POST | X-Admin-Key | Clone a key (new key, same config, fresh counters) | | /keys/usage | GET | X-Admin-Key | Per-key usage breakdown (per-tool, time-series, deny reasons) | | /keys/rotate | POST | X-Admin-Key | Rotate key (new key, same credits/ACL/quotas) | | /keys/acl | POST | X-Admin-Key | Set tool ACL (whitelist/blacklist) on a key | | /keys/expiry | POST | X-Admin-Key | Set or remove key expiry (TTL) | | /keys/quota | POST | X-Admin-Key | Set usage quota (daily/monthly limits) | | /keys/tags | POST | X-Admin-Key | Set key tags/metadata (merge semantics) | | /keys/ip | POST | X-Admin-Key | Set IP allowlist (CIDR + exact match) | | /keys/search | POST | X-Admin-Key | Search keys by tag values | | /keys/auto-topup | POST | X-Admin-Key | Configure or disable auto-topup for a key | | /admin/keys | GET | X-Admin-Key (super_admin) | List all admin keys (masked) | | /admin/keys | POST | X-Admin-Key (super_admin) | Create a new admin key with role | | /admin/keys/revoke | POST | X-Admin-Key (super_admin) | Revoke an admin key | | /limits | POST | X-Admin-Key | Set spending limit on a key | | /usage | GET | X-Admin-Key | Export usage data (JSON or CSV) | | /status | GET | X-Admin-Key | Full dashboard with usage stats | | /dashboard | GET | None (admin key in-browser) | Real-time admin web dashboard | | /stripe/checkout | POST | X-API-Key | Create Stripe Checkout Session for credit purchase | | /stripe/packages | GET | None | List available credit packages (public, rate-limited) | | /stripe/webhook | POST | Stripe Signature | Auto-top-up credits on payment | | /admin/backup | GET | X-Admin-Key | Export full server state as versioned JSON snapshot | | /admin/restore | POST | X-Admin-Key | Import state from backup (merge/overwrite/full modes) | | /admin/cache | GET | X-Admin-Key | Response cache stats (entries, hits, misses, hit rate) | | /admin/cache | DELETE | X-Admin-Key | Clear cache (all or ?tool= filter) | | /admin/circuit | GET | X-Admin-Key | Circuit breaker status (state, failures, rejections) | | /admin/circuit | POST | X-Admin-Key | Reset circuit breaker to closed state | | /.well-known/oauth-authorization-server | GET | None | OAuth 2.1 server metadata | | /oauth/register | POST | None | Dynamic Client Registration (RFC 7591) | | /oauth/authorize | GET | None | Authorization endpoint (PKCE required) | | /oauth/token | POST | None | Token endpoint (code exchange + refresh) | | /oauth/revoke | POST | None | Token revocation (RFC 7009) | | /oauth/clients | GET | X-Admin-Key | List registered OAuth clients | | /.well-known/mcp-payment | GET | None | Server payment metadata (SEP-2007) | | /.well-known/mcp.json | GET | None | MCP Server Identity card (discovery) | | /pricing | GET | None | Full per-tool pricing breakdown | | /openapi.json | GET | None | OpenAPI 3.1 spec (all 140+ endpoints) | | /docs | GET | None | Interactive API docs (Swagger UI) | | /robots.txt | GET | None | Crawler directives (allow public, disallow admin/keys) | | /portal | GET | None | Self-service API key portal (browser UI, auth via X-API-Key prompt) | | /ready | GET | None | Readiness probe (200 when ready, 503 when draining/maintenance) | | /metrics | GET | None | Prometheus metrics (counters, gauges, uptime) | | /analytics | GET | X-Admin-Key | Usage analytics (time-series, tool breakdown, trends) | | /alerts | GET | X-Admin-Key | Consume pending alerts | | /alerts | POST | X-Admin-Key | Configure alert rules | | /teams | GET | X-Admin-Key | List all teams | | /teams | POST | X-Admin-Key | Create a team (name, budget, quota, tags) | | /teams/update | POST | X-Admin-Key | Update team settings | | /teams/delete | POST | X-Admin-Key | Delete (deactivate) a team | | /teams/assign | POST | X-Admin-Key | Assign an API key to a team | | /teams/remove | POST | X-Admin-Key | Remove an API key from a team | | /teams/usage | GET | X-Admin-Key | Team usage summary with member breakdown | | /tokens | POST | X-Admin-Key | Create a scoped token (short-lived, tool-restricted) | | /tokens/revoke | POST | X-Admin-Key | Revoke a scoped token (by full token string) | | /tokens/revoked | GET | X-Admin-Key | List all revoked token entries | | /namespaces | GET | X-Admin-Key | List all namespaces with key/credit/spending stats | | /audit | GET | X-Admin-Key | Query audit log (filter by type, actor, time) | | /audit/export | GET | X-Admin-Key | Export full audit log (JSON or CSV) | | /audit/stats | GET | X-Admin-Key | Audit log statistics | | /plugins | GET | X-Admin-Key | List registered plugins with hook info | | /groups | GET | X-Admin-Key | List all key groups (policy templates) | | /groups | POST | X-Admin-Key | Create a key group with shared policies | | /groups/update | POST | X-Admin-Key | Update group policies | | /groups/delete | POST | X-Admin-Key | Delete (deactivate) a group | | /groups/assign | POST | X-Admin-Key | Assign an API key to a group | | /groups/remove | POST | X-Admin-Key | Remove an API key from a group | | /webhooks/filters | GET | X-Admin-Key | List all webhook filter rules | | /webhooks/filters | POST | X-Admin-Key | Create a webhook filter rule | | /webhooks/filters/update | POST | X-Admin-Key | Update a webhook filter rule | | /webhooks/filters/delete | POST | X-Admin-Key | Delete a webhook filter rule | | /webhooks/replay | POST | X-Admin-Key | Replay dead letter webhook events (all or by index) | | /webhooks/test | POST | X-Admin-Key | Send test event to configured webhook URL (synchronous) | | /webhooks/log | GET | X-Admin-Key | Webhook delivery log with status, timing, and filters | | /webhooks/pause | POST | X-Admin-Key | Pause webhook delivery (events buffered until resumed) | | /webhooks/resume | POST | X-Admin-Key | Resume webhook delivery and flush buffered events | | /keys/alias | POST | X-Admin-Key | Set or clear a human-readable alias for an API key | | /keys/expiring | GET | X-Admin-Key | List keys expiring within a time window (?within=86400 seconds) | | /keys/templates | GET | X-Admin-Key | List all key templates | | /keys/templates | POST | X-Admin-Key | Create or update a key template | | /keys/templates/delete | POST | X-Admin-Key | Delete a key template | | /config/reload | POST | X-Admin-Key | Hot-reload config file (pricing, rate limits, webhooks, quotas) | | /health | GET | None | Health check (status, uptime, version, in-flight, Redis/webhook status) | | / | GET | None | Root endpoint (endpoint list) |

Free Methods

These MCP methods pass through without auth or billing: initialize, initialized, ping, tools/list, resources/list, prompts/list

Gated methods: tools/call (single), tools/call_batch (batch — all-or-nothing billing, parallel execution). See Batch Tool Calls.

CLI Options

--server <cmd>       MCP server command to wrap via stdio
--remote-url <url>   Remote MCP server URL (Streamable HTTP transport)
--port <n>           HTTP port (default: 3402)
--price <n>          Default credits per tool call (default: 1)
--rate-limit <n>     Max calls/min per key (default: 60, 0=unlimited)
--name <s>           Server display name
--shadow             Shadow mode — log without enforcing payment
--admin-key <s>      Set admin key (default: auto-generated)
--tool-price <t:n>   Per-tool price (e.g. "search:5,generate:10")
--import-key <k:c>   Import existing key with credits (e.g. "pg_abc:100")
--state-file <path>  Persist keys/credits to a JSON file (survives restarts)
--stripe-secret <s>  Stripe webhook signing secret (enables /stripe/webhook)
--webhook-url <url>  POST batched usage events to this URL
--webhook-secret <s> HMAC-SHA256 secret for signing webhook payloads
--refund-on-failure  Refund credits when downstream tool call fails
--redis-url <url>    Redis URL for distributed state (e.g. "redis://localhost:6379")
--config <path>      Load settings from a JSON config file

Note: Use --server OR --remote-url for single-server mode. Use servers in a config file for multi-server mode.

Persistent Storage

Add --state-file to save API keys and credits to disk. Data survives server restarts.

npx paygate-mcp wrap --server "your-mcp-server" --state-file ~/.paygate/state.json

Stripe Integration

Connect Stripe to automatically top up credits when customers pay:

npx paygate-mcp wrap \
  --server "your-mcp-server" \
  --state-file ~/.paygate/state.json \
  --stripe-secret "whsec_your_stripe_webhook_secret"

Setup:

  1. Create a Stripe Checkout Session with metadata:
    • paygate_api_key — the customer's API key (e.g. pg_abc123...)
    • paygate_credits — credits to add on payment (e.g. 500)
  2. Point your Stripe webhook to https://your-server/stripe/webhook
  3. Subscribe to checkout.session.completed and invoice.payment_succeeded events

When a customer completes payment, credits are automatically added to their API key. Subscriptions auto-renew credits on each billing cycle.

Security:

  • HMAC-SHA256 signature verification (Stripe's v1 scheme)
  • Timing-safe comparison to prevent timing attacks
  • 5-minute timestamp tolerance to prevent replay attacks
  • Payment status verification (only paid triggers credits)
  • Zero dependencies — uses Node.js built-in crypto

Per-Tool ACL (Access Control)

Control which tools each API key can access:

# Create a key that can only access search and read tools
curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "limited-client", "credits": 100, "allowedTools": ["search", "read_file"]}'

# Create a key with specific tools blocked
curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "safe-client", "credits": 100, "deniedTools": ["delete_file", "admin_reset"]}'

# Update ACL on an existing key
curl -X POST http://localhost:3402/keys/acl \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "allowedTools": ["search"], "deniedTools": ["admin"]}'
  • allowedTools (whitelist): Only these tools are accessible. Empty = all tools.
  • deniedTools (blacklist): These tools are always denied. Applied after allowedTools.
  • ACL also filters tools/list — clients only see their permitted tools.

Per-Tool Rate Limits

Set independent rate limits per tool (on top of the global limit):

{
  "toolPricing": {
    "expensive_analyze": { "creditsPerCall": 10, "rateLimitPerMin": 5 },
    "search": { "creditsPerCall": 1, "rateLimitPerMin": 30 },
    "cheap_read": { "creditsPerCall": 1 }
  }
}

Per-tool limits are enforced independently per API key. A key can be rate-limited on one tool while still accessing others. The global --rate-limit applies across all tools.

Key Expiry (TTL)

Create API keys that auto-expire:

# Create a key that expires in 1 hour (3600 seconds)
curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "trial-user", "credits": 50, "expiresIn": 3600}'

# Create a key with a specific expiry date
curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "quarterly", "credits": 1000, "expiresAt": "2026-06-01T00:00:00Z"}'

# Set or extend expiry on an existing key
curl -X POST http://localhost:3402/keys/expiry \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "expiresIn": 86400}'

# Remove expiry (key never expires)
curl -X POST http://localhost:3402/keys/expiry \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "expiresAt": null}'

Expired keys return a clear api_key_expired error. Admins can extend or remove expiry at any time.

Credit Transfers

Atomically transfer credits between API keys:

curl -X POST http://localhost:3402/keys/transfer \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from": "pg_source_key", "to": "pg_dest_key", "credits": 500, "memo": "Monthly allocation" }'

Response:

{
  "transferred": 500,
  "from": { "keyMasked": "pg_sour...key1", "balance": 500 },
  "to": { "keyMasked": "pg_dest...key2", "balance": 700 },
  "memo": "Monthly allocation",
  "message": "Transferred 500 credits"
}

Validation: Both keys must exist, be active (not revoked/expired), and the source must have sufficient credits. Fractional credits are floored to integers. Self-transfers are rejected.

Audit trail: Every transfer logs a key.credits_transferred audit event with masked keys, amount, balances, and memo.

Bulk Key Operations

Execute multiple key operations (create, topup, revoke) in a single request. Failed operations don't stop subsequent ones — each result includes success status and index for easy correlation.

curl -X POST http://localhost:3402/keys/bulk \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      { "action": "create", "name": "api-key-1", "credits": 500, "tags": { "env": "prod" } },
      { "action": "create", "name": "api-key-2", "credits": 200 },
      { "action": "topup", "key": "pg_existing_key", "credits": 1000 },
      { "action": "revoke", "key": "pg_old_key" }
    ]
  }'

Response:

{
  "total": 4,
  "succeeded": 4,
  "failed": 0,
  "results": [
    { "index": 0, "action": "create", "success": true, "result": { "key": "pg_abc...", "name": "api-key-1", "credits": 500 } },
    { "index": 1, "action": "create", "success": true, "result": { "key": "pg_def...", "name": "api-key-2", "credits": 200 } },
    { "index": 2, "action": "topup", "success": true, "result": { "creditsAdded": 1000, "newBalance": 1500 } },
    { "index": 3, "action": "revoke", "success": true, "result": { "message": "Key revoked" } }
  ]
}

Actions: create (with optional name, credits, tags, namespace, allowedTools, deniedTools), topup (key + credits), revoke (key). Unknown actions return an error result without stopping the batch.

Limits: Maximum 100 operations per request. Empty operations array returns 400.

Audit trail: Each successful operation logs an individual audit event with "(bulk)" suffix.

Key Import/Export

Export all API keys for backup or migration between PayGate instances:

# Export as JSON (includes full key secrets)
curl http://localhost:3402/keys/export \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -o paygate-keys-backup.json

# Export as CSV
curl "http://localhost:3402/keys/export?format=csv" \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -o paygate-keys-backup.csv

# Export only active keys in a specific namespace
curl "http://localhost:3402/keys/export?activeOnly=true&namespace=production" \
  -H "X-Admin-Key: $ADMIN_KEY"

Import keys into a PayGate instance:

curl -X POST http://localhost:3402/keys/import \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keys": [{ "key": "pg_abc123...", "name": "my-key", "credits": 500, "active": true, "tags": {} }],
    "mode": "skip"
  }'

Response:

{
  "total": 1,
  "imported": 1,
  "overwritten": 0,
  "skipped": 0,
  "errors": 0,
  "mode": "skip",
  "results": [{ "key": "pg_abc123...", "name": "my-key", "status": "imported" }]
}

Conflict modes: skip (default) — skip keys that already exist, overwrite — replace existing keys, error — fail on duplicate keys.

Limits: Maximum 1000 keys per import request. Keys must start with pg_ prefix.

Export formats: JSON (full records with all fields) or CSV (key subset for spreadsheet use).

Spending Limits

Cap the total credits any API key can spend:

# Set a spending limit on a key (admin only)
curl -X POST http://localhost:3402/limits \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "spendingLimit": 500}'

# Check remaining budget
curl http://localhost:3402/balance -H "X-API-Key: CLIENT_API_KEY"
# → { "spendingLimit": 500, "remainingBudget": 350, ... }

Set spendingLimit to 0 for unlimited. When a key hits its limit, tool calls are denied with a clear error.

Refund on Failure

Automatically return credits when a downstream tool call fails:

npx paygate-mcp wrap --server "node server.js" --refund-on-failure

Credits are deducted before the tool call. If the wrapped server returns an error, credits are refunded and totalSpent / totalCalls are rolled back. Prevents charging users for failed operations.

Webhook Events

POST usage events to any external URL for billing, alerting, or analytics:

npx paygate-mcp wrap --server "node server.js" --webhook-url "https://billing.example.com/events"

Events are batched (up to 10 per POST) and flushed every 5 seconds. Each event includes tool name, credits charged, API key, and timestamp.

Retry Queue & Dead Letters

Failed webhook deliveries are retried with exponential backoff (1s, 2s, 4s, 8s, 16s — configurable up to --webhook-retries attempts). After all retries are exhausted, events move to a dead letter queue for admin inspection.

# Custom max retries (default: 5)
npx paygate-mcp wrap --server "node server.js" \
  --webhook-url "https://billing.example.com/events" \
  --webhook-retries 10

Admin endpoints:

| Endpoint | Method | Description | |----------|--------|-------------| | /webhooks/stats | GET | Delivery statistics (delivered, failed, pending retries, dead letters) | | /webhooks/dead-letter | GET | List permanently failed deliveries with error details | | /webhooks/dead-letter | DELETE | Clear dead letter queue | | /webhooks/replay | POST | Replay dead letter events (all or by index) |

Retry attempts include an X-PayGate-Retry header with the attempt number for observability.

Webhook Event Replay

Replay permanently failed webhook events from the dead letter queue:

# Replay all dead letter entries
curl -X POST http://localhost:3402/webhooks/replay \
  -H "X-Admin-Key: $ADMIN_KEY"

# Replay specific entries by index
curl -X POST http://localhost:3402/webhooks/replay \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "indices": [0, 2, 5] }'

Replayed entries are removed from the dead letter queue and re-queued for fresh delivery (attempt counter resets to 0). If delivery fails again, they follow the normal retry/dead-letter flow.

Webhook Signatures (HMAC-SHA256)

Sign webhook payloads for tamper-proof delivery:

npx paygate-mcp wrap --server "node server.js" \
  --webhook-url "https://billing.example.com/events" \
  --webhook-secret "whsec_your_secret_here"

When --webhook-secret is set, every webhook POST includes an X-PayGate-Signature header:

X-PayGate-Signature: t=1709123456,v1=a1b2c3d4...

Verifying signatures (Node.js example):

import { WebhookEmitter } from 'paygate-mcp';

const signature = req.headers['x-paygate-signature'];
const [tPart, v1Part] = signature.split(',');
const timestamp = tPart.split('=')[1];
const sig = v1Part.split('=')[1];

// Reconstruct signed payload: timestamp.body
const signedPayload = `${timestamp}.${rawBody}`;
const isValid = WebhookEmitter.verify(signedPayload, sig, 'whsec_your_secret_here');

The signature covers timestamp.body to prevent replay attacks. Use timing-safe comparison (built into WebhookEmitter.verify).

Admin Lifecycle Events

When webhooks are enabled, admin operations also fire webhook events:

| Event Type | Trigger | Metadata | |------------|---------|----------| | key.created | POST /keys | keyMasked, name, credits | | key.topup | POST /topup | keyMasked, creditsAdded, newBalance | | key.revoked | POST /keys/revoke | keyMasked | | key.rotated | POST /keys/rotate | oldKeyMasked, newKeyMasked | | key.expired | Gate evaluation | keyMasked | | alert.fired | Gate evaluation | alertType, keyPrefix, message, value, threshold | | team.created | POST /teams | teamId, name, budget | | team.updated | POST /teams/update | teamId, changes | | team.deleted | POST /teams/delete | teamId | | team.key_assigned | POST /teams/assign | teamId, keyMasked | | team.key_removed | POST /teams/remove | teamId, keyMasked |

Admin events appear in the adminEvents array of the webhook payload (separate from usage events). Both arrays can be present in the same batch.

Webhook Filters (Event Routing)

Route webhook events to different destinations based on event type and API key prefix. Each filter rule routes matching events to its own URL with independent retry queues, dead letter queues, and optional signing secrets.

Create a filter rule:

curl -X POST http://localhost:3402/webhooks/filters \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-alerts",
    "events": ["key.created", "key.revoked", "alert.fired"],
    "url": "https://alerts.example.com/webhook",
    "secret": "whsec_alerts_secret",
    "keyPrefixes": ["pk_prod_"],
    "active": true
  }'

List filters:

curl http://localhost:3402/webhooks/filters -H "X-Admin-Key: $ADMIN_KEY"

Update a filter:

curl -X POST http://localhost:3402/webhooks/filters/update \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "wf_abc123", "active": false }'

Delete a filter:

curl -X POST http://localhost:3402/webhooks/filters/delete \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "wf_abc123" }'

Filter rules:

  • events — Array of event types to match (exact match or "*" wildcard for all events)
  • keyPrefixes — Optional array of API key prefixes (e.g., ["pk_prod_"]). Events only match if the associated key starts with one of these prefixes. Omit for all keys.
  • url — Destination URL for matched events (each unique URL gets its own retry queue)
  • secret — Optional HMAC-SHA256 signing secret for this destination
  • active — Enable/disable the filter without deleting it

Routing behavior:

  • Events matching filter rules are sent to the filter's destination URL
  • The default webhook URL (if configured) always receives all events (backward compatible)
  • Multiple filters can match the same event — it's sent to all matching destinations
  • Inactive filters are skipped during routing

Config file:

{
  "webhookUrl": "https://billing.example.com/events",
  "webhookFilters": [
    {
      "name": "production-alerts",
      "events": ["key.created", "key.revoked", "alert.fired"],
      "url": "https://alerts.example.com/webhook",
      "keyPrefixes": ["pk_prod_"]
    }
  ]
}

Stats: GET /webhooks/stats includes per-URL delivery statistics for all filter destinations plus the default endpoint.

Usage Quotas

Set daily or monthly usage limits per API key:

# Create a key with 10 calls/day, 200 calls/month
curl -X POST http://localhost:3402/keys \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"name": "metered-user", "credits": 1000, "quota": {"dailyCallLimit": 10, "monthlyCallLimit": 200}}'

# Set credit-based quotas (max 50 credits/day)
curl -X POST http://localhost:3402/keys/quota \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "dailyCreditLimit": 50}'

# Remove per-key quota (fall back to global defaults)
curl -X POST http://localhost:3402/keys/quota \
  -H "Content-Type: application/json" \
  -H "X-Admin-Key: YOUR_ADMIN_KEY" \
  -d '{"key": "CLIENT_API_KEY", "remove": true}'

Quota types: dailyCallLimit, monthlyCallLimit, dailyCreditLimit, monthlyCreditLimit. Set to 0 for unlimited. Counters reset at UTC midnight (daily) and UTC month boundary (monthly). Set global defaults in the config file with globalQuota.

Dynamic Pricing

Charge extra credits based on input argument size:

{
  "toolPricing": {
    "analyze_text": { "creditsPerCall": 2, "creditsPerKbInput": 5 },
    "search": { "creditsPerCall": 1 }
  }
}

For analyze_text, a 3 KB input would cost 2 + ceil(3 × 5) = 17 credits. Small inputs round up to at least 1 KB. Tools without creditsPerKbInput use the flat base price.

OAuth 2.1

Full OAuth 2.1 authorization server for MCP clients. Implements PKCE, dynamic client registration, token refresh, and revocation.

Enable OAuth in config:

{
  "oauth": {
    "accessTokenTtl": 3600,
    "refreshTokenTtl": 2592000,
    "scopes": ["tools:*", "tools:read", "tools:write"]
  }
}

Full flow:

# 1. Register an OAuth client
curl -X POST http://localhost:3402/oauth/register \
  -H "Content-Type: application/json" \
  -d '{"client_name": "My Agent", "redirect_uris": ["http://localhost:8080/callback"], "api_key": "pg_..."}'

# 2. Generate PKCE challenge (code_verifier → SHA256 → base64url)
# 3. Authorize: GET /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&code_challenge=...&code_challenge_method=S256
# 4. Exchange code for tokens
curl -X POST http://localhost:3402/oauth/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type": "authorization_code", "code": "...", "client_id": "...", "redirect_uri": "...", "code_verifier": "..."}'

# 5. Use Bearer token on /mcp
curl -X POST http://localhost:3402/mcp \
  -H "Authorization: Bearer pg_at_..." \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "search", "arguments": {"query": "hello"}}}'

# 6. Refresh token
curl -X POST http://localhost:3402/oauth/token \
  -d '{"grant_type": "refresh_token", "refresh_token": "pg_rt_...", "client_id": "..."}'

OAuth tokens are backed by API keys — each token maps to an API key for billing. The /mcp endpoint accepts both X-API-Key and Authorization: Bearer headers.

SSE Streaming (MCP Streamable HTTP)

PayGate implements the full MCP Streamable HTTP transport with SSE support:

# POST /mcp with SSE response (add Accept header)
curl -N -X POST http://localhost:3402/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"analyze","arguments":{}}}'
# Response: SSE stream with event: message + data: {jsonrpc response}

# GET /mcp — Open SSE notification stream
curl -N http://localhost:3402/mcp \
  -H "Accept: text/event-stream" \
  -H "Mcp-Session-Id: mcp_sess_..."
# Receives server-initiated notifications as SSE events

# DELETE /mcp — Terminate session
curl -X DELETE http://localhost:3402/mcp \
  -H "Mcp-Session-Id: mcp_sess_..."

Session Management:

  • Every POST /mcp response includes an Mcp-Session-Id header
  • Clients reuse sessions by sending Mcp-Session-Id on subsequent requests
  • GET /mcp opens a long-lived SSE connection for server-to-client notifications
  • DELETE /mcp terminates a session and closes all SSE connections
  • Sessions auto-expire after 30 minutes of inactivity

Transport modes:

  • POST /mcp without Accept: text/event-stream → standard JSON response (backward compatible)
  • POST /mcp with `A