Documentation
Docs API Reference SDKs Guides Changelog Status
v4.1
Log in Dashboard →

Prynt API Reference

The Prynt API is organized around REST. All requests and responses use JSON. Authentication is via Bearer token. All API access is over HTTPS.

Base URLhttps://api.prynt.io/v1

All endpoints require authentication. Include your secret key as a Bearer token in the Authorization header. The API returns standard HTTP status codes and JSON error bodies.

Authentication

The Prynt API uses Bearer token authentication. Include your secret key in the Authorization header of every request. Secret keys carry full API access — keep them secure.

API Keys

KeyPrefixUsage
Public Keypk_live_Used in client SDKs (browser / mobile). Safe to expose in frontend code.
Secret Keysk_live_Used server-side for the REST API. Never expose in client code or version control.
Test Keyspk_test_ / sk_test_Sandbox environment. No real data. Use for development and testing.
🔒
Never expose your secret key. If compromised, rotate immediately in Settings → API Keys. All previously issued keys are revoked instantly.
Request Header
Authorization
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
cURL Example
Shell
curl https://api.prynt.io/v1/events/req_xxx \
  -H "Authorization: Bearer sk_live_xxx..."
Node.js SDK
server.js
import { PryntServer } from '@prynt/node';

const prynt = new PryntServer({
  secretKey: process.env.PRYNT_SECRET_KEY,
});

Errors

Prynt uses standard HTTP status codes. Errors include a JSON body with code, message, and docs link.

Status codes

CodeMeaningDescription
200OKRequest succeeded.
400Bad RequestInvalid parameters, malformed JSON, or missing required field.
401UnauthorizedMissing, invalid, or revoked API key.
403ForbiddenValid key but insufficient permissions for this endpoint.
404Not FoundResource doesn't exist or has expired.
429Rate LimitedToo many requests. Check Retry-After header.
500Server ErrorInternal error. Retry with exponential backoff.
Error Response
401 Unauthorized
{
  "error": {
    "code":    "invalid_api_key",
    "message": "The API key is invalid or revoked.",
    "docs":    "https://docs.prynt.io/errors#invalid_api_key"
  }
}
Rate Limit Error
429 Too Many Requests
{
  "error": {
    "code":    "rate_limited",
    "message": "Rate limit exceeded. Retry in 12s.",
    "retryAfter": 12
  }
}
Validation Error
400 Bad Request
{
  "error": {
    "code":    "validation_error",
    "message": "'conditions' is required.",
    "field":   "conditions"
  }
}

📥Events

Events represent individual identification requests. Each call to identify() creates one event linked to a persistent visitor ID.

GET/v1/events/{requestId}

Retrieve an event

Returns the full identification result for a single event — visitor ID, device data, Smart Signals, ML scores, and rules engine verdict. This is the primary endpoint for server-side verification.

Path parameters

ParameterTypeDescription
requestIdRequiredstringThe request ID returned by identify(). Format: req_*

Response fields

requestIdstring
Unique identifier for this event.
visitorIdstring
Persistent device identifier. Stable across sessions, incognito, and cookie clearing.
confidencefloat
Identification confidence, 0 to 1. Values above 0.9 are high-certainty.
visitorFoundboolean
Whether this visitor has been identified before.
deviceobject
Device metadata — platform, browser, GPU, screen, OS. Additional mobile fields from native SDKs.
signalsobject
Smart Signals — bot, vpn, incognito, tampered, emulator, proxy, tor, rootedDevice, clonedApp.
scoresobject
ML risk scores: abuse (0–1), ato (0–1), bot (0–1), suspect (0–100). Pro plan and above.
ipobject
IP intelligence — address, geolocation (city, country, lat/lng), ASN, blocklist status.
verdictstring | null
allow, challenge, or block. Null if no rules are configured.
matchedRuleobject | null
The rule that triggered the verdict — ID, name, and priority. Null if no match.
firstSeenAtdatetime
ISO 8601 timestamp of the visitor's first identification.
timestampdatetime
ISO 8601 timestamp of this event.
Request
Node.js
const event = await prynt.getEvent(
  'req_1707832921_a7f2c9'
);
cURL
curl https://api.prynt.io/v1/events/req_1707832921_a7f2c9 \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "requestId":    "req_1707832921_a7f2c9",
  "visitorId":    "pv_8kX2mNqR3jT7p",
  "confidence":   0.995,
  "visitorFound": true,
  "firstSeenAt":  "2025-09-14T08:12:33Z",
  "timestamp":    "2026-02-14T11:45:22Z",
  "device": {
    "platform":  "macOS",
    "browser":   "Chrome 121",
    "gpu":       "Apple M3 Pro",
    "type":      "desktop",
    "screen": { "w": 2560, "h": 1440 }
  },
  "signals": {
    "bot":       { "detected": false },
    "vpn":       { "detected": false,
                   "provider": null },
    "incognito": false,
    "tampered":  false,
    "emulator":  false,
    "proxy":     false,
    "tor":       false
  },
  "scores": {
    "abuse":   0.03,
    "ato":     0.01,
    "bot":     0.02,
    "suspect": 4
  },
  "ip": {
    "address":     "73.162.xxx.xxx",
    "city":        "San Francisco",
    "country":     "US",
    "lat":         37.7749,
    "lng":         -122.4194,
    "blocklisted": false
  },
  "verdict":     "allow",
  "matchedRule": null
}
GET/v1/events

List events

Returns a paginated list of identification events with optional filters for visitor ID, time range, verdict, and signals.

Query parameters

ParameterTypeDescription
visitorIdstringFilter by visitor ID.
beforedatetimeReturn events before this ISO 8601 timestamp.
afterdatetimeReturn events after this timestamp.
verdictstringFilter by verdict.
allowchallengeblock
botbooleanFilter for bot-detected events.
limitintegerNumber of results. Max 100.Default: 20
cursorstringPagination cursor from previous response.
Request
cURL
curl "https://api.prynt.io/v1/events?verdict=block&limit=10" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "data": [
    {
      "requestId":  "req_170783...",
      "visitorId":  "pv_8kX2mN...",
      "confidence": 0.995,
      "verdict":    "block",
      "timestamp":  "2026-02-14T11:45Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "cur_abc123..."
}

👤Visitors

A visitor represents a unique device identified by Prynt. Each visitor has a persistent ID and history of all events.

GET/v1/visitors/{visitorId}

Retrieve a visitor

Returns visitor metadata — first seen date, total visit count, device breakdown, associated IPs, and linked accounts.

Response fields

visitorIdstring
The persistent device identifier.
firstSeenAtdatetime
Timestamp of the visitor's first identification.
lastSeenAtdatetime
Timestamp of the most recent identification.
totalVisitsinteger
Total number of identification events for this visitor.
devicesarray
Array of device profiles seen for this visitor.
linkedAccountsinteger
Number of distinct user accounts linked to this device.
listsarray
Lists this visitor belongs to (e.g. trusted_devices, blocklist).
Request
Node.js
const visitor = await prynt.getVisitor(
  'pv_8kX2mNqR3jT7p'
);
Response
200 OK
{
  "visitorId":      "pv_8kX2mNqR3jT7p",
  "firstSeenAt":    "2025-09-14T08:12Z",
  "lastSeenAt":     "2026-02-14T11:45Z",
  "totalVisits":    347,
  "linkedAccounts": 1,
  "devices": [
    {
      "platform": "macOS",
      "browser":  "Chrome 121",
      "gpu":      "Apple M3 Pro"
    }
  ],
  "lists": ["trusted_devices"]
}
DELETE/v1/visitors/{visitorId}

Delete visitor data

Permanently deletes all data associated with a visitor — events, device profiles, list memberships, and analytics. This action is irreversible and intended for GDPR/CCPA data deletion requests.

⚠️
Irreversible. This permanently removes all data for this visitor. The visitor ID will be recycled — future identifications from the same device will generate a new visitor.
Request
cURL
curl -X DELETE \
  https://api.prynt.io/v1/visitors/pv_8kX2mN... \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "deleted":   true,
  "visitorId": "pv_8kX2mNqR3jT7p"
}
GET/v1/visitors/{visitorId}/events

List visitor events

Returns a paginated list of events for a specific visitor. Use this to view the full history of identifications for a single device.

Path parameters

ParameterTypeDescription
visitorIdRequiredstringThe visitor ID. Format: pv_*

Query parameters

ParameterTypeDescription
beforedatetimeReturn events before this ISO 8601 timestamp.
afterdatetimeReturn events after this timestamp.
limitintegerNumber of results. Max 100.Default: 20
Request
cURL
curl "https://api.prynt.io/v1/visitors/pv_8kX2mN.../events?limit=5" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "data": [
    {
      "requestId": "req_1707832921_a7f2c9",
      "timestamp": "2026-02-14T11:45:22Z",
      "verdict":   "allow",
      "signals": {
        "bot": false,
        "vpn": false
      }
    },
    {
      "requestId": "req_1707745678_b8c3d2",
      "timestamp": "2026-02-14T09:12:15Z",
      "verdict":   "allow",
      "signals": {
        "bot": false,
        "vpn": false
      }
    }
  ],
  "hasMore": true
}

⚖️Rules

Rules evaluate conditions against identification events and return verdicts (allow, challenge, block) with optional side effects. Rules are evaluated in priority order.

POST/v1/rules

Create a rule

Creates a new rule with conditions, action, optional side effects, and status. Rules propagate globally in under 2 seconds after creation.

Request body

FieldTypeDescription
nameRequiredstringHuman-readable rule name. Max 200 chars.
conditionsRequiredobjectCondition tree with operator (AND/OR) and rules array. Each rule has field, operator, value.
actionRequiredobjectAction config with verdict and optional sideEffects array.
priorityintegerEvaluation order. Lower = evaluated first.Default: next available
statusstringActivation status.
livemonitordraft
Default: draft

Condition operators

equalsnot_equalsgtgteltlteinnot_incontainsexists

Side effect types

addToListremoveFromListwebhookslacklog
Request Body
POST /v1/rules
{
  "name": "Block Bot Registrations",
  "priority": 1,
  "status": "live",
  "conditions": {
    "operator": "AND",
    "rules": [
      {
        "field": "signals.bot.detected",
        "operator": "equals",
        "value": true
      },
      {
        "field": "event.type",
        "operator": "equals",
        "value": "registration"
      }
    ]
  },
  "action": {
    "verdict": "block",
    "sideEffects": [
      {
        "type": "addToList",
        "list": "blocked_devices"
      }
    ]
  }
}
Response
201 Created
{
  "id":             "rul_9a7f2c4e8b1d",
  "name":           "Block Bot Registrations",
  "priority":       1,
  "status":         "live",
  "createdAt":      "2026-02-14T14:30:00Z",
  "propagated":     true,
  "propagationMs":  1840
}
GET/v1/rules

List rules

Returns all rules for the workspace, ordered by priority. Filter by status to view only active, paused, or draft rules.

Query parameters

ParameterTypeDescription
statusstringFilter by rule status.
livepauseddraft
limitintegerNumber of results to return.
offsetintegerPagination offset.
Request
cURL
curl "https://api.prynt.io/v1/rules?status=live" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "data": [
    {
      "id":         "rul_9a7f2c4e8b1d",
      "name":       "Block Bot Registrations",
      "status":     "live",
      "priority":   1,
      "conditions": {
        "operator": "AND",
        "count":    2
      },
      "action":     "block",
      "createdAt":  "2026-02-14T14:30:00Z"
    },
    {
      "id":         "rul_8b6c3d2e9f1a",
      "name":       "Challenge High-Risk Logins",
      "status":     "live",
      "priority":   2,
      "conditions": {
        "operator": "OR",
        "count":    3
      },
      "action":     "challenge",
      "createdAt":  "2026-02-13T10:15:00Z"
    }
  ]
}
GET/v1/rules/{ruleId}

Retrieve a rule

Returns a single rule with full conditions and metadata, including match statistics.

Path parameters

ParameterTypeDescription
ruleIdRequiredstringThe rule ID. Format: rul_*

Response fields

idstring
Unique rule identifier.
namestring
Human-readable rule name.
conditionsobject
Full conditions array with operator and rules.
actionobject
Action configuration with verdict and side effects.
sideEffectsarray
Optional side effects triggered when rule matches.
statsobject
Match count and last match timestamp.
Request
cURL
curl https://api.prynt.io/v1/rules/rul_9a7f... \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "id":         "rul_9a7f2c4e8b1d",
  "name":       "Block Bot Registrations",
  "status":     "live",
  "priority":   1,
  "conditions": {
    "operator": "AND",
    "rules": [
      {
        "field":    "signals.bot.detected",
        "operator": "equals",
        "value":    true
      },
      {
        "field":    "event.type",
        "operator": "equals",
        "value":    "registration"
      }
    ]
  },
  "action": {
    "verdict": "block",
    "sideEffects": [
      {
        "type": "addToList",
        "list": "blocked_devices"
      }
    ]
  },
  "stats": {
    "matchCount":  8429,
    "lastMatchAt": "2026-02-14T14:22:10Z"
  },
  "createdAt": "2026-02-14T14:30:00Z"
}
PUT/v1/rules/{ruleId}

Update a rule

Updates a rule. Partial updates are supported — only include the fields you want to change. Changes propagate globally in approximately 2 seconds.

Path parameters

ParameterTypeDescription
ruleIdRequiredstringThe rule ID. Format: rul_*

Request body

FieldTypeDescription
namestringHuman-readable rule name. Max 200 chars.
conditionsobjectCondition tree with operator and rules array.
actionobjectAction config with verdict and optional sideEffects.
priorityintegerEvaluation order. Lower = evaluated first.
statusstringActivation status.
livemonitordraft
sideEffectsarraySide effects array. Replaces existing side effects entirely.
Request
PUT
curl -X PUT \
  https://api.prynt.io/v1/rules/rul_9a7f... \
  -H "Authorization: Bearer sk_live_..." \
  -d '{
    "status": "paused"
  }'
Response
200 OKapplication/json
{
  "id":             "rul_9a7f2c4e8b1d",
  "name":           "Block Bot Registrations",
  "status":         "paused",
  "priority":       1,
  "updatedAt":      "2026-02-14T15:00:00Z",
  "propagated":     true,
  "propagationMs":  1920
}
DELETE/v1/rules/{ruleId}

Delete a rule

Permanently deletes a rule. Active rules are disabled immediately and the rule is removed from the evaluation engine. This action is irreversible.

Path parameters

ParameterTypeDescription
ruleIdRequiredstringThe rule ID. Format: rul_*
⚠️
Irreversible. Deleted rules cannot be recovered. Consider pausing the rule instead if you may want to re-enable it later.
Request
cURL
curl -X DELETE \
  https://api.prynt.io/v1/rules/rul_9a7f... \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "deleted": true,
  "ruleId":  "rul_9a7f2c4e8b1d"
}
POST/v1/rules/{ruleId}/backtest

Backtest a rule

Runs a rule against up to 30 days of historical events. Returns match count, affected visitors, estimated false positive rate, and a sample of matched events. Use to validate rules before enabling in production.

Request body

FieldTypeDescription
daysintegerNumber of days to look back. Max 30.Default: 7
sampleSizeintegerNumber of matched events to include in sample. Max 100.Default: 10

Response fields

matchCountinteger
Total events that would have matched this rule.
totalEventsinteger
Total events in the lookback window.
matchRatefloat
Percentage of events that matched (0 to 1).
estimatedFprfloat
Estimated false positive rate based on signal distribution analysis.
samplearray
Sample of matched events with visitor IDs and timestamps.
Request
POST
curl -X POST \
  https://api.prynt.io/v1/rules/rul_9a7f.../backtest \
  -H "Authorization: Bearer sk_live_..." \
  -d '{ "days": 30, "sampleSize": 5 }'
Response
200 OK
{
  "ruleId":       "rul_9a7f2c4e8b1d",
  "matchCount":   84291,
  "totalEvents":  1284102,
  "matchRate":    0.0656,
  "estimatedFpr": 0.0002,
  "days":         30,
  "durationMs":   4821,
  "sample": [
    {
      "requestId": "req_170xxx...",
      "visitorId": "pv_4xN7q...",
      "timestamp": "2026-02-13T09:12Z"
    }
  ]
}

📋Lists

Dynamic allow/block/review lists. Reference lists in rule conditions to build persistent policies. Entries are visitor IDs, IP addresses, or emails.

POST/v1/lists

Create a list

Creates a new list for grouping visitors, IPs, or emails. Use in rule conditions with the in and not_in operators.

Request body

FieldTypeDescription
nameRequiredstringList name. Used in rule conditions. Must be unique, snake_case recommended.
typeRequiredstringEntry type.
visitoripemail
descriptionstringOptional description for dashboard display.
ttlintegerAuto-expire entries after this many seconds. Null for permanent.Default: null
Request
POST /v1/lists
{
  "name": "blocked_devices",
  "type": "visitor",
  "description": "Confirmed fraud devices",
  "ttl": 2592000
}
Response
201 Created
{
  "id":          "lst_f3a8c7d2e1b4",
  "name":        "blocked_devices",
  "type":        "visitor",
  "entryCount":  0,
  "ttl":         2592000,
  "createdAt":   "2026-02-14T15:00Z"
}
GET/v1/lists

List all lists

Returns all lists in the workspace. Filter by type to view only visitor, IP, or email lists.

Query parameters

ParameterTypeDescription
typestringFilter by list type.
visitoripemail
limitintegerNumber of results to return.
offsetintegerPagination offset.
Request
cURL
curl "https://api.prynt.io/v1/lists?type=visitor" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OKapplication/json
{
  "data": [
    {
      "id":          "lst_f3a8c7d2e1b4",
      "name":        "blocked_devices",
      "type":        "visitor",
      "entryCount":  47,
      "createdAt":   "2026-02-14T15:00Z",
      "updatedAt":   "2026-02-14T16:30Z"
    },
    {
      "id":          "lst_a2b3c4d5e6f7",
      "name":        "trusted_devices",
      "type":        "visitor",
      "entryCount":  128,
      "createdAt":   "2026-02-10T09:15Z",
      "updatedAt":   "2026-02-14T12:10Z"
    }
  ]
}
PATCH/v1/lists/{listId}/entries

Update list entries

Add or remove entries from a list in a single atomic operation. Supports bulk operations up to 1,000 entries per call.

Request body

FieldTypeDescription
addarrayEntries to add. Each entry is a string (visitor ID, IP, or email depending on list type).
removearrayEntries to remove.
Request
PATCH
{
  "add": [
    "pv_8kX2mNqR3jT7p",
    "pv_4xN7qKmR9sT2p"
  ],
  "remove": [
    "pv_old_visitor_id"
  ]
}
Response
200 OK
{
  "listId":     "lst_f3a8c7d2e1b4",
  "added":      2,
  "removed":    1,
  "entryCount": 47
}
DELETE/v1/lists/{listId}

Delete a list

Permanently deletes a list and all its entries. Rules referencing this list will no longer match on list conditions.

Path parameters

ParameterTypeDescription
listIdRequiredstringThe list ID to delete. Format: lst_*
Request
cURL
curl -X DELETE \
  https://api.prynt.io/v1/lists/lst_f3a8c7... \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "deleted": true,
  "listId":  "lst_f3a8c7d2e1b4"
}

🔔Webhooks

Receive real-time event notifications via HTTP POST. Configure filters to subscribe only to events matching specific verdicts, signals, or rules.

POST/v1/webhooks

Create a webhook

Registers an endpoint to receive real-time event data. Prynt signs every payload with HMAC-SHA256 for verification. Failed deliveries are retried with exponential backoff for up to 24 hours.

Request body

FieldTypeDescription
urlRequiredstringEndpoint URL. Must be HTTPS.
eventsarrayEvent types to subscribe to.
identificationrule_matchlist_update
Default: all events
filtersobjectOptional filters: verdict, ruleId, botDetected. Only matching events are sent.
secretstringSigning secret for HMAC-SHA256 payload verification. Auto-generated if omitted.
💡
Verify signatures. Every webhook POST includes an X-Prynt-Signature header. Verify the HMAC-SHA256 digest of the raw body against this header using your signing secret.
Request
POST /v1/webhooks
{
  "url": "https://your-app.com/webhooks/prynt",
  "events": ["identification", "rule_match"],
  "filters": {
    "verdict": ["block", "challenge"]
  }
}
Response
201 Created
{
  "id":        "whk_c4e8b1d2a7f3",
  "url":       "https://your-app.com/...",
  "status":    "active",
  "secret":    "whsec_xxxxxxxxxxxxxx",
  "createdAt": "2026-02-14T15:30Z"
}
Webhook Payload (what you receive)
POSTto your endpoint
{
  "event":     "identification",
  "timestamp": "2026-02-14T15:32Z",
  "data": {
    "requestId": "req_170xxx...",
    "visitorId": "pv_8kX2mN...",
    "verdict":   "block",
    "signals":   { /* ... */ }
  }
}
GET/v1/webhooks

List webhooks

Returns all configured webhooks for the workspace.

Query parameters

ParameterTypeDescription
statusstringFilter by status.
activepaused
limitintegerNumber of results. Max 100.Default: 20
offsetintegerOffset for pagination.Default: 0
Request
cURL
curl "https://api.prynt.io/v1/webhooks?status=active" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "data": [
    {
      "id":             "whk_c4e8b1d2a7f3",
      "url":            "https://your-app.com/...",
      "events":        ["identification", "rule_match"],
      "status":         "active",
      "createdAt":      "2026-02-14T15:30Z",
      "lastDeliveryAt": "2026-02-15T07:12Z",
      "successRate":    0.998
    }
  ],
  "total": 1
}
PUT/v1/webhooks/{id}

Update a webhook

Updates a webhook configuration. Use to change URL, events filter, or pause/resume delivery.

Path parameters

ParameterTypeDescription
idRequiredstringThe webhook ID. Format: whk_*

Request body

FieldTypeDescription
urlstringNew endpoint URL. Must be HTTPS.
eventsarrayEvent types to subscribe to.
statusstringSet to paused to stop deliveries or active to resume.
activepaused
Request
PUT
{
  "status": "paused"
}
Response
200 OK
{
  "id":        "whk_c4e8b1d2a7f3",
  "url":       "https://your-app.com/...",
  "events":    ["identification", "rule_match"],
  "status":    "paused",
  "updatedAt": "2026-02-15T07:45Z"
}
DELETE/v1/webhooks/{id}

Delete a webhook

Permanently removes a webhook. Pending deliveries are cancelled immediately.

Path parameters

ParameterTypeDescription
idRequiredstringThe webhook ID to delete. Format: whk_*
Request
cURL
curl -X DELETE \
  https://api.prynt.io/v1/webhooks/whk_c4e8b1... \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "deleted":   true,
  "webhookId": "whk_c4e8b1d2a7f3"
}

📊Analytics

Query aggregated event and signal data for dashboards, reporting, and trend analysis. Supports time-series, grouping, and filtering.

GET/v1/analytics/events

Query event analytics

Returns aggregated event counts and metrics over a time range. Group by verdict, platform, country, or hour/day/week. Use for building dashboards and monitoring fraud trends.

Query parameters

ParameterTypeDescription
fromRequireddatetimeStart of time range (ISO 8601).
toRequireddatetimeEnd of time range.
groupBystringAggregation dimension.
verdictplatformcountryhourdayweek
verdictstringFilter by verdict.
Request
cURL
curl "https://api.prynt.io/v1/analytics/events?from=2026-02-07T00:00:00Z&to=2026-02-14T00:00:00Z&groupBy=verdict" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "from":   "2026-02-07T00:00Z",
  "to":     "2026-02-14T00:00Z",
  "total":  1284102,
  "groups": [
    {
      "verdict": "allow",
      "count":   1187421,
      "pct":     0.9247
    },
    {
      "verdict": "challenge",
      "count":   48290,
      "pct":     0.0376
    },
    {
      "verdict": "block",
      "count":   48391,
      "pct":     0.0377
    }
  ]
}
GET/v1/analytics/signals

Query Smart Signal analytics

Returns aggregated Smart Signal detection counts and trends. Use for monitoring signal distribution and detection rates.

Query parameters

ParameterTypeDescription
fromRequireddatetimeStart of time range (ISO 8601).
toRequireddatetimeEnd of time range.
groupBystringAggregation dimension.
signaldayweek
signalstringFilter by specific signal name (e.g., bot, vpn, incognito).
Request
cURL
curl "https://api.prynt.io/v1/analytics/signals?from=2026-02-01T00:00:00Z&to=2026-02-15T00:00:00Z&groupBy=signal" \
  -H "Authorization: Bearer sk_live_..."
Response
200 OK
{
  "from":   "2026-02-01T00:00Z",
  "to":     "2026-02-15T00:00Z",
  "total":  2847291,
  "signals": [
    {
      "signal": "bot",
      "count":  84291,
      "rate":   0.0296,
      "trend":  "up"
    },
    {
      "signal": "vpn",
      "count":  12847,
      "rate":   0.0045,
      "trend":  "stable"
    },
    {
      "signal": "incognito",
      "count":  47821,
      "rate":   0.0168,
      "trend":  "down"
    }
  ]
}

Rate Limits

The API enforces per-key rate limits to ensure fair usage. Limits vary by plan and endpoint. Rate limit status is included in response headers.

Response headers

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window.
X-RateLimit-RemainingRequests remaining in current window.
X-RateLimit-ResetUnix timestamp when the window resets.
Retry-AfterSeconds to wait before retrying (only on 429 responses).

Limits by plan

PlanServer APIMgmt APIBurst
Starter100/min30/min10/sec
Pro1,000/min100/min50/sec
EnterpriseCustomCustomCustom
Rate Limit Headers
Response Headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1707836400
Content-Type: application/json
Node.js — Retry on 429
retry.js
async function withRetry(fn, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (e) {
      if (e.status !== 429) throw e;
      const wait = e.retryAfter ?? 2 ** i;
      await new Promise(
        r => setTimeout(r, wait * 1000)
      );
    }
  }
}