API Reference v1

Push key activity events from your system to KeyPulse. We track them, score them, and alert you when something looks wrong. Integration takes under 5 minutes.

Base URL
https://keypulse-5pj5.polsia.app

Quick Start

Send your first event in under 30 seconds.

1

Get your API key

Sign up for early access at keypulse-5pj5.polsia.app. Your key will arrive by email — it starts with kp_live_.

2

Send an event

One POST call is all it takes to start tracking activity:

curl -X POST https://keypulse-5pj5.polsia.app/api/events \
  -H "Authorization: Bearer kp_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "key_id": "my-signing-key-01",
    "event_type": "signing_request",
    "severity": "nominal",
    "source_ip": "10.0.0.1",
    "actor": "service-account@myapp.com"
  }'
import requests

response = requests.post(
    "https://keypulse-5pj5.polsia.app/api/events",
    headers={
        "Authorization": "Bearer kp_live_your_key_here",
        "Content-Type": "application/json"
    },
    json={
        "key_id": "my-signing-key-01",
        "event_type": "signing_request",
        "severity": "nominal",
        "source_ip": "10.0.0.1",
        "actor": "service-account@myapp.com"
    }
)

print(response.json())
const response = await fetch("https://keypulse-5pj5.polsia.app/api/events", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kp_live_your_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    key_id: "my-signing-key-01",
    event_type: "signing_request",
    severity: "nominal",
    source_ip: "10.0.0.1",
    actor: "service-account@myapp.com"
  })
});

const data = await response.json();
console.log(data);
3

Watch it appear in real-time

Open the Dashboard and watch your event stream live via SSE.

Authentication

All protected endpoints require a Bearer token in the Authorization header. Keys are issued per company and scoped to a single tenant.

Authorization: Bearer kp_live_<your_40_char_key>
Key Security

Keys are shown once at creation. Store them in environment variables — never hardcode in source. If a key is compromised, contact support to revoke it immediately.

Endpoints

All endpoints are under https://keypulse-5pj5.polsia.app/api. Protected endpoints require a valid API key. Public endpoints (marked below) do not.

POST /api/events Ingest a single key activity event

Request Body

FieldTypeRequiredDescription
key_id string Required Identifier for the key this event relates to (e.g. signing-key-01)
event_type string Required Type of activity: signing_request, key_access, rotation, export, policy_change, or any custom string
severity string Required Risk level: nominal | warning | critical
source_ip string Optional IP address of the originating request
actor string Optional Identity that triggered the event (service account, user email, system name)
details object Optional Arbitrary JSON metadata for this event (stored as-is, queryable later)

Example Response

{
  "success": true,
  "id": 4821,
  "key_id": "my-signing-key-01",
  "event_type": "signing_request",
  "severity": "nominal",
  "source_ip": "10.0.0.1",
  "actor": "service-account@myapp.com",
  "details": {},
  "created_at": "2026-04-05T12:34:00.000Z",
  "alerts_triggered": 0
}
POST /api/events/batch Ingest multiple events in one request

Send up to 100 events in a single call. Each event in the array follows the same schema as POST /api/events.

Request Body

FieldTypeRequiredDescription
events array Required Array of event objects. Max 100 per request. Each object follows the same schema as single event ingestion.

Example

curl -X POST https://keypulse-5pj5.polsia.app/api/events/batch \
  -H "Authorization: Bearer kp_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "key_id": "key-01", "event_type": "signing_request", "severity": "nominal" },
      { "key_id": "key-02", "event_type": "export", "severity": "warning", "actor": "auditor" },
      { "key_id": "key-01", "event_type": "rotation", "severity": "nominal" }
    ]
  }'
const response = await fetch("https://keypulse-5pj5.polsia.app/api/events/batch", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kp_live_your_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    events: [
      { key_id: "key-01", event_type: "signing_request", severity: "nominal" },
      { key_id: "key-02", event_type: "export", severity: "warning" }
    ]
  })
});
GET /api/events Query historical events with filters

Query Parameters

ParamTypeRequiredDescription
key_id string Optional Filter by specific key identifier
event_type string Optional Filter by event type (e.g. signing_request)
severity string Optional Filter by severity: nominal | warning | critical
limit integer Optional Max results to return (default: 50, max: 500)

Example

curl "https://keypulse-5pj5.polsia.app/api/events?severity=critical&limit=20" \
  -H "Authorization: Bearer kp_live_your_key_here"
GET /api/keys List all monitored keys and their event counts

Returns all keys associated with your account, including event counts and the last activity timestamp.

Example Response

{
  "success": true,
  "keys": [
    {
      "id": 1,
      "name": "Production Signing Key",
      "key_type": "mpc_shard",
      "status": "active",
      "event_count": 412,
      "last_activity": "2026-04-05T11:23:00.000Z"
    }
  ]
}
GET /api/stats Public dashboard statistics

Returns aggregate stats for the dashboard. No auth required — this endpoint is public.

Example Response

{
  "total_keys": 24,
  "total_events": 18304,
  "events_24h": 847,
  "severity_breakdown": {
    "nominal": 16022,
    "warning": 1981,
    "critical": 301
  }
}

Event Schema

Every event stored in KeyPulse has the following shape:

key_id string
Your identifier for the key being tracked. Free-form — use whatever naming convention fits your infra.
event_type string
Category of activity.
signing_request key_access rotation export policy_change custom_string
severity enum
Risk level of the event. Drives alert rule evaluation and dashboard coloring.
nominal warning critical
source_ip string
IPv4 or IPv6 address of the request origin. Used by the unusual IP alert rule type.
actor string
Identity that caused the event — service account, email, or system name. Displayed in the event log.
details object
Arbitrary JSON payload stored with the event. Pass anything relevant — transaction hashes, request IDs, metadata.
id integer (auto)
Auto-incremented primary key. Returned in every response — use it for deduplication.
created_at timestamp (auto)
UTC timestamp set by the server when the event is received.

Full Example

{
  "id": 4821,
  "key_id": "prod-signing-key-01",
  "event_type": "signing_request",
  "severity": "nominal",
  "source_ip": "10.0.14.22",
  "actor": "tx-processor@custody.internal",
  "details": {
    "tx_hash": "0xabc123...",
    "chain": "ethereum",
    "amount_usd": 42500
  },
  "created_at": "2026-04-05T12:34:00.000Z"
}

Rate Limits

Default rate limit is 100 requests per minute per API key. Limits are enforced at the key level — multiple keys for the same company are each tracked independently.

Response Headers

Every response includes these headers so you can track your current window:

X-RateLimit-Limit
Total requests allowed in this window
X-RateLimit-Remaining
Requests remaining in current window
X-RateLimit-Reset
Unix timestamp when the window resets

If you exceed your limit, the API returns 429 Too Many Requests. Use the batch endpoint to reduce call volume when ingesting high-frequency events.

Error Codes

All errors follow a consistent shape:

{ "success": false, "message": "Human-readable error description" }
Status When it happens What to do
200 / 201 Request succeeded
400 Missing required field or invalid value (e.g. bad severity) Check request body against the schema
401 Missing or invalid Authorization header Add Authorization: Bearer <key>
403 Key is revoked or inactive Contact support to issue a new key
429 Rate limit exceeded (100 req/min default) Back off and retry after X-RateLimit-Reset
500 Server error Retry with exponential backoff. If persistent, contact support.
KeyPulse API v1 · Updated April 2026
Dashboard Support Home