Scoring API
Real-time ML scoring endpoints — first-user payer conversion (Starter Pack popup). Six features, 30-min post-install scoring, top-N% bucket output for in-session targeting.
Overview
The Scoring API exposes real-time machine-learning endpoints for in-session player-targeting decisions. The first available model is the First-User Payer Conversion scorer — designed to drive the Starter Pack popup decision at the 30-minute post-install mark.
Send six behavioural features from a new install's first 30 minutes, get back a score in [0,1] and a bucket label (top_1pct / top_5pct / top_10pct / rest) for operational thresholding. Fire the popup on top_5pct-or-higher for ~8× lift over base rate.
| Endpoint | Method | Description |
|---|---|---|
/v1/scoring/first-user-conversion | POST | Score D1 payer probability from first-30-min behaviour |
Authentication
All scoring endpoints require a client-side API key with the scoring:write scope.
| Header | Value | Notes |
|---|---|---|
X-API-Key | pk_live_v1_... | Client (pk_) key. Server (sk_) keys also accepted. |
Content-Type | application/json | |
Accept | application/json |
scoring:write return 403. Contact your account team to grant the scope on existing keys.First-User Conversion
Predicts the probability that a new install will pay within their first day (D1). Use the bucket label to drive in-session offers like the Starter Pack popup.
Request
curl -X POST class="code-string">"https:class="code-commentclass="code-string">">//api.ilara.ai/v1/scoring/first-user-conversion" \-H class="code-string">"X-API-Key: pk_live_v1_xxx" \-H class="code-string">"Content-Type: application/json" \-d '{class="code-string">"devtodev_id": class="code-string">"DCD5D755-E12C-4E3C-9010-CDAE3232B059",class="code-string">"loot_distinct_types": 3,class="code-string">"sess_duration_total": 500.0,class="code-string">"match_avg_fight_time": 45.0,class="code-string">"match_wins": 4,class="code-string">"install_hour": 14,class="code-string">"vpay_count": 2}'
Request body
One identity field plus six behavioural features observed in the first 30 minutes post-install. Every feature defaults to 0 — omit fields you don't have, never send null.
| Field | Type | Required | Description |
|---|---|---|---|
devtodev_id | string (1-64) | Yes | The DevToDev anonymous user ID. Echoed in the response; stored with the score. |
loot_distinct_types | int | No (0) | Count of distinct _LootcaseType values opened in the first 30 minutes. Top predictor — ~35% of model gain. |
sess_duration_total | float (sec) | No (0) | Sum of activityduration across session-END events. Excludes idle/background time. NOT wall-clock elapsed time. |
match_avg_fight_time | float (sec) | No (0) | Mean of _FightTime across all matches. NOT total match duration including loading. |
match_wins | int | No (0) | Count of matches where _Result == "WIN" (exact uppercase). |
install_hour | int 0-23 | No (0) | Hour-of-day of install. UTC. Not IST, not device-local. |
vpay_count | int | No (0) | Count of ALL virtual-currency events (earns + spends of in-game currency). NOT real-money in-app purchases. |
Response
{class="code-string">"success": true,class="code-string">"data": {class="code-string">"devtodev_id": class="code-string">"DCD5D755-E12C-4E3C-9010-CDAE3232B059",class="code-string">"score": 0.0823,class="code-string">"bucket": class="code-string">"top_5pct",class="code-string">"model_version": class="code-string">"19423a2fc71c",class="code-string">"thresholds_used": {class="code-string">"top_1pct": 0.0992,class="code-string">"top_5pct": 0.0795,class="code-string">"top_10pct": 0.0673},class="code-string">"scored_at": class="code-string">"2026-05-20T14:30:00.913Z"},class="code-string">"error": null,class="code-string">"meta": null}
| Field | Type | Description |
|---|---|---|
devtodev_id | string | Echoed from the request. |
score | float [0,1] | Model probability the user pays within D1. |
bucket | enum | One of top_1pct, top_5pct, top_10pct, rest. |
model_version | string | sha256[:12] of the artifact. Rotates with each retrain. |
thresholds_used | object | The 99/95/90th-percentile cutoffs used to assign the bucket. Read these from the response; do NOT hardcode. |
scored_at | RFC 3339 | UTC timestamp when the score was computed. |
Bucket Semantics
Buckets are computed from the model's out-of-fold score distribution and rotate with each retrain. Read thresholds_used from every response — don't hardcode the cutoffs.
| Bucket | Approx score ≥ | Payer probability (D1) | Recommended action |
|---|---|---|---|
| top_1pct | ~0.099 | ~47% | Fire popup; highest confidence |
| top_5pct | ~0.080 | ~23% | Fire popup; standard cohort |
| top_10pct | ~0.067 | ~9% | Optional cheaper offer |
| rest | < 0.067 | <3% | No popup; base rate cohort |
bucket in {top_1pct, top_5pct} captures most paying users with minimal popup fatigue.Call Timing
The model is trained on features observed in the user's first 30 minutes post-install. Score at 30 minutes (or at end-of-first-session, whichever fires first) for the calibration the model expects.
| Field | ≤15m | ≤30m | ≤60m | ≤24h |
|---|---|---|---|---|
loot_distinct_types | 82.5% | 83.3% | 83.9% | 86.3% |
sess_duration_total | 90.6% | 97.2% | 99.1% | 99.4% |
match_avg_fight_time | 88.5% | 89.0% | 89.4% | 90.9% |
match_wins | 88.4% | 89.0% | 89.3% | 90.8% |
install_hour | 100% | 100% | 100% | 100% |
vpay_count | 83.2% | 83.9% | 84.6% | 86.9% |
At 30 minutes, 81% of users (and 92% of payers) have all 6 fields populated. Scoring earlier than 30 minutes is supported but drops ROC-AUC below 0.75 — only do so if the popup must fire in-FTUE.
Model Card
Headline metrics for the current production artifact:
| Metric | Value |
|---|---|
| Training cohort | 20,048 iOS-US users (Mar 1 – Apr 30 2026) |
| Positives (D1 payers) | 519 (2.59% base rate) |
| Features | 6 numeric |
| ROC-AUC (out-of-fold) | 0.8044 |
| PR-AUC (out-of-fold) | 0.2667 |
| Lift @ top 1% | 18.26× |
| Lift @ top 5% | 8.94× |
| Cross-validation | 5-fold StratifiedKFold |
| HPO objective | PR-AUC (50 Optuna TPE trials) |
| p95 latency | < 50 ms |
| Artifact size | 82 KB (model.joblib) |
Field-Definition Gotchas
Six places where a backend-side bug will silently send values that don't match what the model was trained on. Confirm each with your engineering team before integration:
- install_hour must be UTC, not IST or device-local. Off-by-5.5h on every score otherwise.
- sess_duration_total uses the
activitydurationfield on session-END events, not wall-clock elapsed time and not the (start_ts, end_ts) difference.activitydurationexcludes idle. - match_wins counts the exact uppercase string
"WIN"."Win"and"win"are not matched. - vpay_count covers ALL virtual-currency events (earns + spends of in-game currency), NOT real-money IAPs. Sending IAP-count instead will yield values ~10× smaller than training.
- loot_distinct_types counts distinct values of
_LootcaseType. Use the same enumeration as devtodev exports. - Omit fields you don't have — send
0if you must, nevernull. Pydantic strict-types numerics and 422s on null.
Error Responses
| Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid X-API-Key |
| 403 | FORBIDDEN | API key lacks the scoring:write scope |
| 422 | VALIDATION_ERROR | Body validation failed (e.g. install_hour=24, null in numeric field) |
| 503 | MODEL_UNAVAILABLE | Scoring artifact failed to load — retry after 30s |
Operational Notes
Idempotency
The endpoint is not idempotent in v1 — client-side retries produce additional ml_scores rows for the same devtodev_id. Don't retry on 422; retry once after 30s on 503.
Persistence
Every score is persisted asynchronously to our ml_scores table (within ~1 s of the HTTP response) with devtodev_id, score, bucket, model_fingerprint, the raw feature payload, and the game/tenant context. Available for A/B attribution joins.
Rate limits
Rate limit follows the standard tier scheme (1000 rpm for growth, 10000 for pro, unmetered for enterprise). For high-volume integrations, contact your account team — we can right-size dedicated capacity.
Next Steps
- Authentication — API key types and the
scoring:writescope - Events API — Track behaviour that feeds future scoring models
- Churn Prediction — Complementary lifecycle modelling