Public API Reference
Complete reference for the Checkpoint REST API
Overview
The Checkpoint Public API provides programmatic access to detection services, project data, and analytics. Endpoints are RESTful and use JSON. Most endpoints require API key authentication; the public client-ingestion endpoints (/event, /pixel, /pixel/track) authenticate by project/pixel ID in the request body instead — see Authentication.
Scope of this page. It documents the /api/v1 endpoints that a customer integration normally
calls, which is a subset of the full surface. Deliberately not covered here — these route
families back internal tooling, other codebases, or dashboard-only flows, and are not part of the
supported public contract: webhooks/*, fingerprint/*, gateway/*, molti/*, openclaw/*,
wink/*, vault/*, search, policy, middleware/policy, and audit/*. The remainder — plus
everything under /api/internal/* — backs the dashboard itself. If you need an endpoint that
isn't listed here, treat it as unsupported rather than undocumented.
Base URL
All API requests should be made to:
https://kya.vouched.id/api/v1For local development:
http://localhost:3000/api/v1Authentication
Checkpoint uses API keys to authenticate requests. See Credentials for where to find your Project ID and API key.
Include your API key in the request header:
curl -X POST https://kya.vouched.id/api/v1/detect \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"userAgent": "Mozilla/5.0..."}'const response = await fetch('https://kya.vouched.id/api/v1/detect', {
method: 'POST',
headers: {
'X-API-Key': 'your_api_key_here',
'Content-Type': 'application/json',
},
body: JSON.stringify({ userAgent: 'Mozilla/5.0...' }),
});import requests
response = requests.post(
'https://kya.vouched.id/api/v1/detect',
headers={
'X-API-Key': 'your_api_key_here',
'Content-Type': 'application/json',
},
json={'userAgent': 'Mozilla/5.0...'},
)Which endpoints need a key?
| Endpoints | Auth |
|---|---|
/detect, /batch, /log-detection, /enforce, /projects/*, /shopify/projects/*, /bouncer/* | API key (X-API-Key) |
/event, /pixel, /pixel/track | Public — authenticated by the project/pixel ID in the body |
Exceptions inside /bouncer/* (each authenticated by its flow rather than an API key, by design): the user-facing consent link (GET /bouncer/authorize) and delegation status polling (GET /bouncer/delegations/status/{requestId}) are public; delegation token retrieval authenticates with Authorization: Bearer <delegation_token>; delegation creation (POST /bouncer/projects/{projectId}/delegations) is part of the browser-based consent flow; the OAuth token endpoint (POST /bouncer/oauth/token) authenticates with the single-use authorization code it exchanges; and the OAuth callback (GET /bouncer/oauth/callback) is the provider's redirect target, validated by its state parameter.
Core Detection APIs
Detect AI Agent
Analyzes a request to determine if it originates from an AI agent, bot, or human.
Endpoint: POST /api/v1/detect
Auth: API key (X-API-Key), read permission.
Request Body:
{
"userAgent": "Mozilla/5.0 AppleWebKit/537.36 (compatible; GPTBot/1.2; +https://openai.com/gptbot)",
"ipAddress": "203.0.113.7",
"headers": {
"accept": "*/*"
},
"url": "https://example.com/pricing",
"method": "GET"
}Only userAgent is required. Optional fields: ipAddress (falls back to the connecting IP when omitted), headers, url, method, behavioralData, requestId, timestamp, and options (mode: strict | balanced | lenient, includeMetadata, includeBreakdown).
Response:
{
"success": true,
"data": {
"result": {
"isAgent": true,
"confidence": 92,
"detectionClass": { "type": "AiAgent", "agentType": "chatgpt" },
"reasons": ["User agent matched known AI agent pattern"],
"signals": [],
"detectedAgent": { "type": "chatgpt", "name": "ChatGPT-User" },
"verificationMethod": "pattern",
"timestamp": "2026-07-27T12:00:00.000Z"
},
"metadata": {
"processingTime": 12,
"wasmUsed": true,
"cacheHit": false
}
},
"metadata": {
"requestId": "req_abc123",
"timestamp": "2026-07-27T12:00:00.000Z"
}
}data.result is the detection detail. data.breakdown (a per-method confidence breakdown) is included when options.includeBreakdown is set, and data.behavioralAnalysis (isHumanLike, confidence, patterns, anomalies) is included when the request carried behavioralData.
Detection Classes:
result.detectionClass is a tagged object — match on its type:
type | Description |
|---|---|
Human | Regular browser traffic |
AiAgent | AI assistants and crawlers (ChatGPT, Claude, Perplexity) — may carry agentType, vendor, model |
Bot | Traditional bots (search engines, scrapers, monitoring) — may carry botType, legitimacy |
IncompleteData | Insufficient signals for classification |
The wire schema also declares Automation and Unknown, but the detection engine never emits either — treat them as dead values, not classes to branch on.
Confidence Scores:
Scores range from 0–100. See Confidence Distribution for guidance on threshold selection.
Errors: 401 AUTH_MISSING_CREDENTIALS / AUTH_INVALID_API_KEY / AUTH_EXPIRED_API_KEY (see
Common Error Codes for the shared shape), 429 RATE_LIMIT_EXCEEDED once
your plan's per-minute limit is exceeded, 400 VALIDATION_INVALID_REQUEST when the body fails
schema validation (e.g. missing userAgent).
Event Tracking
Send Event
Records a tracking event for analytics.
Endpoint: POST /api/v1/event
Auth: Public — authenticated by the pixelId in the body (no API key required).
Request Body:
{
"pixelId": "b1c2d3e4-5678-90ab-cdef-1234567890ab",
"sessionId": "session_abc",
"url": "https://example.com/page",
"userAgent": "Mozilla/5.0...",
"referrer": "https://google.com",
"metadata": { "custom": "data" }
}Required fields: pixelId (UUID), sessionId, url, userAgent. Returns { success, eventId, sessionId, detection }.
Response status: 200, or 403 with the response body itself (not the standard error envelope)
when the project's blockOnHighConfidence setting is on and this event's confidence exceeds the
configured threshold.
Errors: 404 PIXEL_NOT_FOUND for an invalid pixelId, 403 PIXEL_DISABLED for a disabled
pixel, 403 PIXEL_DOMAIN_NOT_ALLOWED when the pixel has an allowedDomains list configured and
the event's URL doesn't match, 429 RATE_LIMIT_EXCEEDED.
Batch Events
Send multiple events in a single request.
Endpoint: POST /api/v1/batch
Auth: API key (X-API-Key), write permission.
Each event uses the same shape as Send Event — every event must include its own pixelId. Maximum 100 events per batch.
Request Body:
{
"events": [
{
"pixelId": "b1c2d3e4-...",
"sessionId": "s1",
"url": "https://example.com/p1",
"userAgent": "Mozilla/5.0..."
},
{
"pixelId": "b1c2d3e4-...",
"sessionId": "s2",
"url": "https://example.com/p2",
"userAgent": "Mozilla/5.0..."
}
]
}Response: always 200 for a well-formed batch — per-event failures (invalid or disabled
pixel) are reported inside results[] as { success: false, error: { code, message } } rather
than failing the whole request.
Errors: 413 PIXEL_BATCH_TOO_LARGE when events.length exceeds 100, 429 RATE_LIMIT_EXCEEDED,
400 VALIDATION_INVALID_REQUEST for a malformed body. Per-item PIXEL_NOT_FOUND / PIXEL_DISABLED
surface inside results[], not as the top-level error.
Pixel Tracking
Pixel Endpoint
Ingestion endpoint for the Marketing Pixel — the endpoint the pixel JS beacon calls on every page load.
Endpoint: POST /api/v1/pixel
Auth: Public — authenticated by the project/pixel ID (pixelId or projectId) in the body.
Request: a JSON pixel-tracking request — pixelId/projectId, sessionId, url, userAgent, plus optional behavioral and fingerprint signals. This endpoint's request schema (PixelTrackingRequestSchema) is large and internal to the beacon package; it is not itemized field-by-field here. Build against the Marketing Pixel beacon rather than this raw endpoint.
Response: a JSON detection result (classification + confidence). This endpoint is POST/JSON — it does not serve a 1×1 tracking GIF.
Errors: 400 MISSING_PIXEL_ID when pixelId is empty, 400 PROJECT_NOT_FOUND for an
unrecognized project/pixel ID (this endpoint returns 400, not 404, for that case — it's the
one exception among the project-scoped endpoints on this page), 403 INVALID_EDGE_SIGNATURE on a
failed internal Edge-redirect signature check, 429 RATE_LIMIT_EXCEEDED.
Log Detection
Persists a detection produced out-of-band (e.g. by the Gateway Worker) to your dashboard. The middleware SDKs call this after an edge detection so it appears in Analytics.
Endpoint: POST /api/v1/log-detection
Auth: API key (X-API-Key) scoped to a project, read permission.
Request: the detection detail plus request context (and optional enforcement / engine / SDK / identity metadata). The full shape (LogDetectionRequestSchema) mirrors the shared detection-result type rather than a page-specific one and is not itemized field-by-field here.
Response: 202 Accepted immediately — the write happens asynchronously (fire-and-forget). A
202 means the request was accepted, not that the write has completed or succeeded; persistence
failures are logged server-side and are not surfaced back to the caller.
Errors: 401 AUTH_INVALID_API_KEY when the API key has no associated project, 400 VALIDATION_INVALID_REQUEST for a malformed body.
Project Management
List Projects
Get all projects associated with your API key.
Endpoint: GET /api/v1/projects
Auth: API key (X-API-Key). A project-scoped key returns exactly its project; an unscoped key
returns every project across the key owner's organizations. Permission scope (read / write /
admin) does not affect list visibility — it gates what you may do, not what you can see here.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number |
limit | 20 | Results per page (max 100) |
search | — | Search term |
Response:
List endpoints return a paginated envelope — the array is always under data:
{
"success": true,
"data": [
{
"id": "acme-corp",
"name": "My Project",
"createdAt": "2024-01-01T00:00:00.000Z",
"status": "active",
"stats": {
"pixelCount": 2,
"detectionCount": 1234,
"lastDetection": "2024-01-07T09:30:00.000Z"
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 50,
"totalPages": 3,
"hasMore": true
},
"version": "v1",
"timestamp": "2026-07-27T12:00:00.000Z"
}status is active when the project has at least one pixel, otherwise inactive.
Errors: 401 AUTH_MISSING_CREDENTIALS / AUTH_INVALID_API_KEY for missing or invalid keys.
Get Project Details
Endpoint: GET /api/v1/projects/{projectId}
Auth: API key (X-API-Key) with access to this specific project.
Response:
{
"success": true,
"data": {
"id": "acme-corp",
"name": "My Project",
"createdAt": "2024-01-01T00:00:00.000Z",
"status": "active",
"stats": {
"pixelCount": 2,
"detectionCount": 1234,
"lastDetection": "2024-01-07T09:30:00.000Z"
}
},
"version": "v1",
"timestamp": "2026-07-27T12:00:00.000Z"
}Errors: 403 PERMISSION_FORBIDDEN when your API key isn't scoped to this project, 404 PROJECT_NOT_FOUND when the project doesn't exist.
Get Project Detections
Endpoint: GET /api/v1/projects/{projectId}/detections
Auth: API key (X-API-Key) with access to this specific project, read permission.
Query Parameters:
| Parameter | Description |
|---|---|
page | Page number (default 1) |
limit | Results per page (default 50, max 100) |
startDate | Filter start (ISO 8601) |
endDate | Filter end (ISO 8601) |
botType | Filter by detected agent type |
Response:
{
"success": true,
"data": [
{
"id": "det_123",
"timestamp": "2024-01-01T12:00:00.000Z",
"isBot": true,
"confidence": 0.92,
"botType": "ChatGPT",
"userAgent": "Mozilla/5.0...",
"url": "https://example.com"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1000,
"totalPages": 20,
"hasMore": true
},
"version": "v1",
"timestamp": "2026-07-27T12:00:00.000Z"
}On this endpoint confidence is normalized to 0–1 (a 92%-confidence detection is 0.92). The
/detect endpoint returns confidence on the 0–100 scale.
Errors: 403 PERMISSION_FORBIDDEN when your API key isn't scoped to this project, 400 VALIDATION_INVALID_START_DATE / VALIDATION_INVALID_END_DATE / VALIDATION_INVALID_DATE_RANGE
for malformed or inverted date filters.
Get Project Analytics
Endpoint: GET /api/v1/projects/{projectId}/analytics
Auth: API key (X-API-Key) with access to this specific project.
Query Parameters:
| Parameter | Description |
|---|---|
period | Time period (hour, day, week, month; default day) |
startDate | Start date (ISO 8601) |
endDate | End date (ISO 8601) |
Response:
{
"success": true,
"data": {
"period": "day",
"startDate": "2024-01-01",
"endDate": "2024-01-07",
"summary": {
"totalDetections": 10000,
"uniqueBots": 300,
"averageConfidence": 78.5
},
"timeSeries": [
{
"date": "2024-01-01",
"detections": 1500,
"bots": 75,
"humans": 1425
}
],
"botTypes": {
"chatgpt": 45,
"claude": 20,
"googlebot": 10
}
},
"version": "v1",
"timestamp": "2026-07-27T12:00:00.000Z"
}Errors: 400 INVALID_PERIOD for a period outside hour/day/week/month, 400 INVALID_START_DATE / INVALID_END_DATE / INVALID_DATE_RANGE for malformed or inverted date
filters, 500 ANALYTICS_FETCH_ERROR on a downstream aggregation failure.
Managed Deploy
Endpoint: POST /api/v1/deploy/managed
Auth: API key (X-API-Key) with admin permission.
Deploys a KYA-OS agent to Checkpoint's managed hosting on behalf of an existing user, so the deployment appears in that user's dashboard. Built for cross-app integrations — this is not part of the normal dashboard deploy flow.
Request: the body takes projectName (required), template (default "blank"), enableReputation (default true), and at least one user identifier: userEmail or userGithubId. The user must already have a Checkpoint account — the endpoint never creates accounts.
Response: 201 with { projectId, friendlyId, workerUrl, agentDid, ktaClaimUrl, dashboardUrl }. See Deploying a KYA-OS Server for the deployment models.
Errors: 400 VALIDATION_ERROR for a malformed body, 400 MISSING_USER_IDENTIFIER when neither
userEmail nor userGithubId is set, 404 USER_NOT_FOUND when no existing account matches the
identifier (this endpoint never creates one), 400 NO_ORGANIZATION when the matched user has no
organization to deploy into, 400 DEPLOY_FAILED (or a more specific code from the deploy service)
on a failed deployment.
Shopify Endpoints
Public, API-key-authenticated endpoints for the Shopify integration to read and update its own project. See that page for setup; this section documents the wire contract.
Get Shopify Project
Endpoint: GET /api/v1/shopify/projects/{projectId}
Auth: API key (X-API-Key) with access to this project, read permission.
Response: project id, friendlyId, name, domain, settings, stats
(pixelCount/detectionCount/lastDetection), createdAt, updatedAt — a simplified,
public-safe projection of the project record (no sensitive fields).
Errors: 404 PROJECT_NOT_FOUND when the project doesn't exist or was deleted, 403 PERMISSION_FORBIDDEN when your API key isn't scoped to this project.
Update Shopify Project
Endpoint: PATCH /api/v1/shopify/projects/{projectId}
Auth: API key (X-API-Key) with access to this project, write permission.
Request: { settings?: { blockOnHighConfidence?, confidenceThreshold?, enableSessionTracking?, enableWasm? } } — settings are merged with the project's existing settings, not replaced.
Response: the updated project's id, friendlyId, name, domain, settings, updatedAt.
Errors: 400 INVALID_REQUEST for unparsable JSON, 400 VALIDATION_ERROR for a body that fails
ShopifyProjectSettingsUpdateSchema, 404 PROJECT_NOT_FOUND, 403 PERMISSION_FORBIDDEN.
Get Shopify Project Stats
Endpoint: GET /api/v1/shopify/projects/{projectId}/stats
Auth: API key (X-API-Key) with access to this project, read permission.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
startDate | 24 hours ago | ISO date string |
endDate | now | ISO date string |
page | 1 | Page number |
limit | 100 (max 100) | Results per page |
Response: { totalRequests, blockedBots, allowedRequests, threatLevel, recentThreats, pagination }. threatLevel is low / medium / high, derived from the percentage of sessions
classified as AI agents. recentThreats is non-human sessions grouped by
consolidated_session_id, each with a pagesVisited count.
Errors: 404 PROJECT_NOT_FOUND, 403 PERMISSION_FORBIDDEN, 400 INVALID_DATE /
INVALID_DATE_RANGE for malformed or inverted date filters, 500 INTERNAL_DATABASE_ERROR /
STATS_FETCH_ERROR on a downstream failure.
Enforce API
Evaluate Request
Submit a request for enforcement evaluation against your project's policies. This is the endpoint the middleware SDKs call — the project is resolved from your API key, not the body.
Endpoint: POST /api/v1/enforce
Auth: API key (X-API-Key), read permission.
Request Body:
All fields are optional — send what you have:
{
"userAgent": "Mozilla/5.0...",
"ipAddress": "203.0.113.7",
"headers": {},
"path": "/api/data",
"method": "GET",
"options": {
"includeDetectionResult": true
}
}Other accepted fields: url, requestId, action ("get_policy" for a policy-only fetch, omit for detection + enforcement), source, and options.skipDetection / options.cacheTTL.
Response:
{
"success": true,
"data": {
"decision": {
"action": "block",
"reason": "above_threshold",
"isAgent": true,
"confidence": 95,
"agentName": "ChatGPT-User",
"agentType": "chatgpt"
},
"processingTimeMs": 42,
"requestId": "req_abc123",
"detection": {
"isAgent": true,
"confidence": 95,
"detectionClass": "ai_agent",
"agentName": "ChatGPT-User",
"agentType": "chatgpt",
"verificationMethod": "pattern",
"reasons": ["User agent matched known AI agent pattern"]
}
}
}decision.action is one of allow, block, redirect, challenge, or log — rewrite is not part of this set. This endpoint layers two decision sources, and both coerce instruct down to
block before it can reach decision.action:
- The bespoke policy path (deny/allow lists, confidence threshold,
default_action) narrows the stored 6-actiondefault_actionvianarrowToEnforcementAction()(lib/policy/policy-coerce.ts), which mapsinstruct → block. Adefault_actionofchallengesurvives that narrowing but has no execution path yet inresolveAboveThresholdAction()(lib/services/detection-enforcement.service.ts) and also falls back toblock— so the bespoke path alone never returnschallengeeither. - The composed-Cedar layer that can override the bespoke decision (
applyComposedPolicy,lib/services/composed-policy-enforce.service.ts) is the one path that can setaction: "challenge"directly, when the project has Cedar policy authoring enabled and the engine's decision is aChallenge. Its ownInstructdecision is likewise mapped toblock(with the machine-readable guidance folded intodecision.message) because the 5-action enforce wire contract has noinstructvalue.
decision.redirectUrl and decision.message appear when relevant. The detection object is included only when options.includeDetectionResult is set, and there it carries the wire-form detectionClass (human | ai_agent | bot | incomplete_data).
The decision also rides on response headers, so middleware can act without parsing the body:
KYA-Enforce-Action: the decision actionKYA-Processing-Ms: server processing timeKYA-Detection-Method: which detection engine produced the verdict
Errors: 401 AUTH_INVALID_API_KEY when the API key has no associated project, 404 PROJECT_NOT_FOUND / 500 POLICY_FETCH_FAILED on the action: "get_policy" path if the project
can't be resolved, 400 VALIDATION_INVALID_REQUEST for a malformed body.
Bouncer (KYA-OS Governance) APIs
The Bouncer API powers Checkpoint's Govern features — delegations, proofs, OAuth, tool configuration, and consent.
Authorization
Endpoint: GET or POST /api/v1/bouncer/authorize
Auth: GET — none; it's the user-facing consent link the user clicks, with parameters in the
query string. POST — API key (X-API-Key), read permission; same parameters in the body for
server-side callers.
Initiates the delegation authorization flow for an AI agent. Both return an authorization_url (or consent_url for credential and consent-only providers) to send the user to.
Errors: 400 for a malformed request (missing agent_did / requested_scopes, or an
unrecognized provider).
Delegations
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/v1/bouncer/delegations | POST | API key, write | Create a delegation — returns a delegation_token (W3C VC-JWT) |
/api/v1/bouncer/delegations/{delegationId} | DELETE | API key, write | Revoke a delegation |
/api/v1/bouncer/delegations/{delegationId}/tokens | GET | Authorization: Bearer <delegation_token> (not an API key) | Retrieve the delegation's stored OAuth tokens |
/api/v1/bouncer/delegations/verify | POST | API key, read | Verify a delegation and its scopes |
/api/v1/bouncer/delegations/notify | POST | API key, write | Audit-trail upsert from KYA-OS after a direct-mode delegation (fire-and-forget, idempotent) |
/api/v1/bouncer/delegations/status/{requestId} | GET | None — public | Poll delegation request status |
There is no list endpoint here — browse delegations in the dashboard's Delegations page. Revocation is the DELETE route; notify only records delegations created out-of-band. See Managing Delegations for usage examples.
Errors: 401 invalid_token on .../tokens for a missing, malformed, or expired
delegation-token Bearer credential (its own error code, distinct from the API-key AUTH_* codes
used elsewhere on this page); 403 on .../notify when the caller's API key doesn't match the
delegation's project; 404 for an unknown delegationId / requestId; 400 for a malformed
body on the create/verify routes.
OAuth
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/v1/bouncer/oauth/callback | GET | None — the upstream provider's redirect target, validated by its state parameter | Upstream-provider OAuth callback handler |
/api/v1/bouncer/oauth/token | POST | None — authenticates with the single-use authorization code it exchanges | Exchange an authorization code for a delegation token |
See OAuth Integration for the full flow.
Errors: 400 for a missing/invalid authorization code or malformed request, 403 when the
code's scope doesn't match the request, 404 when the underlying delegation record can't be
found, 500 on an unexpected failure.
Identity
Endpoint: POST /api/v1/bouncer/identity/resolve
Auth: API key (X-API-Key), write permission.
Resolves an OAuth identity (provider + subject) to a persistent user DID. Called by KYA-OS servers during OAuth flows.
Errors: 400 for a malformed body, 404 when the identity can't be resolved, 403 when the
API key isn't scoped to the resolved project.
Proofs
Endpoint: POST /api/v1/bouncer/proofs
Auth: API key (X-API-Key), write permission.
Submit KYA-OS cryptographic proofs for verification — signatures are validated, nonces checked, and accepted proofs stored. See Proof Verification.
Errors: 400 for a malformed proof or failed signature/nonce check, 404 when the referenced
delegation or agent can't be found.
Sessions
Endpoint: GET or POST /api/v1/bouncer/sessions
Auth: API key (X-API-Key) — read permission for GET, write permission for POST.
POST registers a session during the KYA-OS handshake so the dashboard can show which MCP clients (Claude Desktop, Cursor, MCP Inspector) are connecting. GET looks up a session by session_id for diagnostics.
Errors: 401 for a missing/invalid API key, 403 when the API key isn't scoped to the
session's project, 404 for an unknown session_id.
Project Configuration
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/v1/bouncer/config | GET | API key | Deprecated legacy global config — use the project-scoped endpoint |
/api/v1/bouncer/projects/{projectId}/config | GET, PUT | API key | Get or update project tool config |
/api/v1/bouncer/projects/{projectId}/config/validate | POST | API key | Validate project config |
/api/v1/bouncer/projects/{projectId}/consent-config | GET | API key | Read consent screen config (edit in the dashboard) |
/api/v1/bouncer/projects/{projectId}/delegations | POST | None — browser-based consent flow (project must exist; rate-limited) | Create project-scoped delegations |
/api/v1/bouncer/projects/{projectId}/providers | GET | API key | List OAuth and credential provider configuration |
See Tool Protection and Consent Flows for usage. In the dashboard, per-tool protection and consent settings are managed at Policy → Auth; tool discovery/removal and per-tool scope display remain on the legacy Control Access surface.
Errors: 404 PROJECT_NOT_FOUND on any project-scoped route in this table when projectId (or
its friendlyId) doesn't resolve; 404 CONSENT_CONFIG_NOT_FOUND on consent-config when the
project has none configured; 403 when the API key isn't scoped to the project.
Rate Limits
Default API rate limits by plan:
| Plan | Requests per Second | Requests per Day* |
|---|---|---|
| Free | 1 | 1,000 |
| Pro | 10 | 50,000 |
| Enterprise | 100 | Unlimited |
* The per-day figure is your plan's quota, not a runtime-enforced limit — live enforcement checks burst, per-second, and per-minute windows only.
Detection responses (/detect) include rate limit headers:
X-RateLimit-Limit: Maximum requests allowed in the per-minute window (this header always reports the minute limit, not the per-second or per-day figures above)X-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Time when limit resets (Unix timestamp)
Enforcement responses (/enforce) carry KYA-* headers instead — see Evaluate Request.
Error Handling
Checkpoint uses standard HTTP status codes and returns errors in a consistent format:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"details": {
"limit": 100,
"reset": 1234567890
}
},
"metadata": {
"requestId": "req_abc123",
"timestamp": "2026-07-27T12:00:00.000Z"
}
}Common Error Codes
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Request validation failed |
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 403 | FORBIDDEN | Access denied to resource |
| 404 | NOT_FOUND | Resource not found |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests |
| 500 | INTERNAL_ERROR | Server error |
SDKs & Packages
Official packages for integration:
| Package | Install |
|---|---|
| Next.js Middleware | npm install @kya-os/checkpoint-nextjs |
| Express Middleware | npm install @kya-os/checkpoint-express |
| .NET Middleware | dotnet add package KyaOs.Checkpoint |
| JavaScript Beacon | npm install @kya-os/checkpoint-beacon |
| Govern Middleware | npm install @kya-os/bouncer-middleware |
See Choose Your Integration for detailed comparison.
Best Practices
- Cache API responses when possible to reduce API calls
- Use batch endpoints for bulk event tracking
- Implement exponential backoff for rate limit errors
- Store API keys securely and rotate them regularly
- Use middleware packages instead of raw API calls for detection
Support
- Email: kya@vouched.id
- Issues: kya+issues@vouched.id