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 identityidentities.get: the identity, its current scores, badges, and attributesidentities.scores: the four category scoresidentities.analysis: the most recent analysis cycle, with observationsidentities.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.