Manual

Server SDKs

The Dregs server SDKs are official clients for calling Dregs from your backend. They send events, read scores, and verify webhooks, using your credential's secret key. Every SDK exposes the same small set of operations, so an integration written in one language reads the same as one written in another.

These are server-side only. Browser tracking stays with the dregs.js script, which uses your public key (pk_) and is what fingerprints devices. The SDKs use your secret key (sk_), which can read identities and scores and must never reach a browser. Most integrations want both: the script in the page, an SDK on the server.

Installing

Language Install Requires
Python pip install dregs Python 3.10+
Node npm install @dregs/sdk Node 20+
Java implementation 'com.dregs:dregs-sdk:0.1.0' Java 17+
Ruby bundle add dregs Ruby 3.1+
PHP composer require dregs/dregs-sdk PHP 8.2+

On npm, the server SDK is @dregs/sdk. The unscoped dregs package is the browser tracking script, which is a different thing and will not read scores.

Each SDK lives in its own repository under github.com/dregs-sdk, where the README carries the full method reference: Python, TypeScript, Java, Ruby, and PHP.

Authenticating

Every SDK reads the secret key from the DREGS_SECRET_KEY environment variable when you do not pass one, so a client usually takes no arguments at all. Find the key under Settings → Credentials; it starts with sk_.

Build one client at startup and reuse it for the life of the process rather than constructing one per request. Every client is safe to share across threads; some also hold a connection pool, which is wasted if you keep making new ones.

# Python
from dregs import Dregs

client = Dregs()
// TypeScript
import { Dregs } from '@dregs/sdk';

const client = new Dregs();
// Java
import com.dregs.sdk.Dregs;

Dregs client = Dregs.builder().build();
# Ruby
require "dregs"

client = Dregs::Client.new
// PHP
use Dregs\Client;

$client = new Client();

Sending an event

The identity is your own id for the user, the same one you pass to dregs.identify() in the browser and the one you look scores up by. It is required: a server-side event carries no device signature, so the identity is the only thing tying the event to a user.

Send user attributes as well as event data wherever you have them. The analyzers lean on attributes such as email, name, and username heavily. Name the keys the way your application already does, then map them to Dregs's canonical fields under Settings → Mappings in the dashboard; the same goes for event names.

# Python
client.track(
    "user.signup",
    identity="user_12345",
    data={"plan": "pro", "referrer": "partner-x"},
    identity_data={"email": "ada@example.com", "name": "Ada Lovelace"},
)
// TypeScript
await client.track('user.signup', {
  identity: 'user_12345',
  data: { plan: 'pro', referrer: 'partner-x' },
  identityData: { email: 'ada@example.com', name: 'Ada Lovelace' },
});
// Java
client.track(TrackRequest.builder("user.signup", "user_12345")
        .data(Map.of("plan", "pro", "referrer", "partner-x"))
        .identityData(Map.of("email", "ada@example.com", "name", "Ada Lovelace"))
        .build());
# Ruby
client.track(
  "user.signup",
  identity: "user_12345",
  data: { plan: "pro", referrer: "partner-x" },
  identity_data: { email: "ada@example.com", name: "Ada Lovelace" }
)
// PHP
$client->track(
    'user.signup',
    identity: 'user_12345',
    data: ['plan' => 'pro', 'referrer' => 'partner-x'],
    identityData: ['email' => 'ada@example.com', 'name' => 'Ada Lovelace'],
);

Idempotency

Every event is sent with an id, which makes ingestion idempotent: reposting the same id returns the original event instead of recording a second one. Pass the id your application already has, such as the row id of the record that triggered the event, and a retry after a timeout can never double-count. The parameter is event_id in Python and Ruby, eventId in TypeScript and PHP, and eventId() on the Java builder; the wire field it sets is id. When you omit it the SDK generates one, which is what makes its own retries safe.

The id must be at most 64 characters and must not start with dregs-, which is reserved for identifiers Dregs generates.

What to send from the server

Send the actions only the server sees: payments and failures, refunds, subscription changes, password resets and changes, role changes, invitations, API key usage, and background jobs the user triggered. Avoid double-counting what the browser already tracks. See Events for the wider picture.

Reading scores

This is the cheap read and the one most integrations want. It returns the four category scores Dregs has already computed, without triggering any work. A category Dregs has not scored yet reads as null, and a brand-new identity comes back empty.

# Python
scores = client.identities.scores("user_12345")

scores.humanity       # 85
scores.authenticity   # 72
scores.uniqueness     # 91
scores.behavior       # 68
// TypeScript
const scores = await client.identities.scores('user_12345');

scores.humanity;      // 85
scores.authenticity;  // 72
// Java
Scores scores = client.identities().scores("user_12345");

scores.humanity();      // 85
scores.authenticity();  // 72
# Ruby
scores = client.identities.scores("user_12345")

scores.humanity       # 85
scores.authenticity   # 72
// PHP
$scores = $client->identities->scores('user_12345');

$scores->humanity();      // 85
$scores->authenticity();  // 72

Scoring is asynchronous. Scores appear moments after the events that move them, not in the same breath. Read them at a decision point, such as when a user reaches for a feature worth protecting, rather than immediately after sending an event.

Seeing exactly why

The scores are the summary; the observations are the evidence. When you need to show or log why an identity scored the way it did, ask for the analysis instead. It returns the most recent analysis cycle with the per-analyzer observations behind each score, and raises a not-found error until the identity has been analyzed at least once.

# Python
analysis = client.identities.analysis("user_12345")

for observation in analysis.observations:
    print(observation.label, observation.explanation, observation.value)

Each observation carries the analyzer that produced it, a value from 0.0 (suspicious) to 1.0 (legitimate), a confidence, a weight, and the counts behind the finding. See Scoring for how observations roll up into the four category scores.

Errors and retries

Each SDK raises a distinct error type per status, all descending from one base type so you can catch broadly when you do not need to distinguish. The two worth handling explicitly on an ingestion path are the monthly event limit (402) and the rate limit (429).

Condition Status
The event was malformed 400
The secret key was not recognized 401
The account is over its monthly event limit 402
The credential may not do this 403
No such identity, or it has not been analyzed 404
Too many requests 429

Connection failures, timeouts, 429s, and 5xx responses are retried automatically with exponential backoff and jitter, honouring the Retry-After header when Dregs sends one. Two retries by default, and configurable. Because every event carries an idempotency id, those retries cannot record an event twice.

Treat tracking as fire-and-forget or queue it. A Dregs outage should never fail your user's request.

Verifying webhooks

Each SDK ships a helper that verifies the X-Dregs-Signature header against the raw request body in constant time, and rejects payloads older than five minutes as replays. Verify against the bytes you received, not a re-serialized object: key order and whitespace change when you re-encode, and the signature will not match.

# Python
from dregs.webhooks import verify

event = verify(
    payload=request.body,
    signature=request.headers["X-Dregs-Signature"],
    secret=os.environ["DREGS_WEBHOOK_SECRET"],
)

The signing secret belongs to the webhook channel and is shown once, when you create it. It is not your API secret key. See Webhooks for the payload shape and headers.

What the SDKs cover

The v1 surface is deliberately small: send events, read an identity and its scores, look at the analysis behind them, queue a rescore, and verify webhooks.

  • track: record a backend event against an identity
  • identities.get: the identity, its current scores, badges, and attributes
  • identities.scores: the four category scores
  • identities.analysis: the most recent analysis cycle, with observations
  • identities.analyze: queue a rescore
  • webhook signature verification

Anything beyond that, such as listing identities, managing escalation rules, channels, or datasets, is available over the REST API, which the SDKs sit on top of. The API is extended additively, so an SDK built against it today keeps working as endpoints are added.

If you would rather have an AI agent do the integration, the Dregs MCP server gives coding agents the same picture of your account, and its setup skills know these SDKs.