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.
https://keypulse-5pj5.polsia.app
Quick Start
Send your first event in under 30 seconds.
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_.
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);
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>
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.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| 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
}
Send up to 100 events in a single call. Each event in the array follows the same schema as POST /api/events.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| 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" } ] }) });
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| 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"
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"
}
]
}
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:
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.
Every response includes these headers so you can track your current window:
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. |