Docs · Reference · API
API reference
Local base URL: http://localhost:8080. On production it's https://api.tellr.com. JSON in and out, UTF-8, ISO 8601 timestamps. No XML, no batch endpoints.
Authentication
Server-to-server requests use a bearer token from Dashboard → API keys. Public keys for the browser SDK travel in a data-key attribute and are scoped to a list of origins.
http
Authorization: Bearer tk_live_a8d2f4e9b1c3d5e7f9a1b3c5d7e9f1a3 Content-Type: application/json
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /v1/check | Run a check (server-to-server) |
GET | /v1/checks/:id | Retrieve one check |
GET | /v1/checks | List checks, cursor-paginated |
POST | /v1/session | Browser SDK posts session signals here |
POST | /v1/users/:id/decisions | Report ground truth back |
GET | /v1/users/:id | Get a tracked user |
GET | /v1/users/by-tellr/:tellr_id | Lookup by 18-digit ID |
GET | /v1/users/:tellr_id/timeline | Full event timeline |
POST | /v1/users/:tellr_id/note | Attach an internal note |
DELETE | /v1/users/:id | GDPR right-to-be-forgotten |
GET / POST / PATCH / DELETE | /v1/rules[/:id] | Manage custom rules |
GET / POST | /v1/webhooks[/:id] | Manage webhooks |
POST | /v1/webhooks/:id/test | Send a test delivery |
POST /v1/check
The only call you make from your backend. session_token is the only required field.
Request
bash
curl -X POST http://localhost:8080/v1/check \
-H "Authorization: Bearer tk_live_••••" \
-H "Content-Type: application/json" \
-d '{
"session_token": "tk_sess_xxx",
"end_user": {
"email": "alice@example.com",
"phone": "+14165550100",
"card_fingerprint": "card_fp_xxx",
"billing_country": "CA"
},
"context": { "trial_plan": "pro_14_day" },
"options": { "include_signals": true, "block_threshold": 80 }
}'Response
json
{
"tellr_id": "194827361092847362",
"check_id": "chk_2K9d3f8",
"verdict": "block",
"score": 87,
"is_repeat": true,
"previous_trials": 2,
"matched_signals": [
{ "type": "hardware_id", "first_seen": "2026-04-12T10:14:00Z" }
],
"explanation": [
{ "signal": "hardware_id_match", "weight": 45, "description": "..." }
],
"thresholds": { "block": 80, "flag": 50 },
"policy_version": "2026-05-01"
}Errors
All errors are 4xx or 5xx with a structured body. Codes are stable.
| Code | HTTP | Meaning |
|---|---|---|
invalid_api_key | 401 | Missing or revoked Authorization header. |
invalid_session_token | 400 | Session token expired or never existed. |
missing_required_field | 400 | A required field is absent from the body. |
rate_limited | 429 | Plan rate limit exceeded. Read Retry-After. |
quota_exceeded | 402 | Monthly check quota used up. Upgrade or wait. |
forbidden_origin | 403 | Browser SDK origin not on the public key allowlist. |
payment_required | 402 | Account billing failed. |
internal_error | 500 | Tellr-side. We page on this. |
Rate limits
Limits apply per project. Exceeding them returns 429 with a Retry-After header in seconds.
| Plan | Per-second | Monthly |
|---|---|---|
| Free | 10 / s | 1,000 |
| Starter | 50 / s | 25,000 |
| Growth | 200 / s | 150,000 |
| Enterprise | negotiated | negotiated |
Idempotency
Pass an Idempotency-Key header to safely retry. Responses are cached for 24 hours and return identical bodies, including the original check_id.