Direct moderation
Asynchronous ingestion is right for scoring users over time. To decide about a piece of content before anyone sees it (a message, a listing, a review), send it with "wait": true: the API records the events, scores the object inline and returns the verdict.
bash
curl -X POST "$API/v1/objects/user-42/events?api_key=$ANALYZE_API_KEY" \
-H "Authorization: Bearer $(sign)" -H 'Content-Type: application/json' \
-d '{"wait":true,"signals":["is_scammer"],
"events":[{"type":"message","content":"pay me by wire and I double it"}]}'ts
const verdict = await analyze.events.ingest("user-42", {
wait: true,
signals: ["is_scammer"],
events: [{ type: "message", content: "pay me by wire and I double it" }],
});
if ("answers" in verdict && (verdict.answers[0]?.noul ?? 0) > 0.9) {
return reject();
}python
verdict = analyze.events.ingest(
"user-42",
wait=True,
signals=["is_scammer"],
events=[{"type": "message", "content": "pay me by wire and I double it"}],
)
if verdict["answers"] and verdict["answers"][0].get("noul", 0) > 0.9:
reject()go
res, err := client.Events.Ingest(ctx, "user-42", &analyze.IngestRequest{
Wait: analyze.Bool(true),
Signals: []string{"is_scammer"},
Events: []analyze.EventInput{{Type: analyze.EventTypeMessage, Content: analyze.String("pay me by wire and I double it")}},
})
if v := res.ModerationVerdict; v != nil && len(v.Answers) > 0 && *v.Answers[0].Noul > 0.9 {
reject()
}php
$verdict = $analyze->events->ingest('user-42', [
'wait' => true,
'signals' => ['is_scammer'],
'events' => [['type' => 'message', 'content' => 'pay me by wire and I double it']],
]);
if (($verdict['answers'][0]['noul'] ?? 0) > 0.9) {
reject();
}The response is 200 OK:
json
{
"object_id": "user-42",
"accepted": 1,
"analyzed": true,
"history_included": true,
"model": "model-1",
"latency_ms": 840,
"answers": [
{ "signal": "is_scammer", "type": "noul", "noul": 0.97 }
]
}Options
signalsscores only the listed signals, which is faster and cheaper than scoring all of them. Omit it to score every enabled signal.include_history(defaulttrue) scores over the object's prior events too. Set it tofalseto judge this content on its own, for example a listing description regardless of who wrote it.
When no configured signal matches, nothing is scored: analyzed is false and reason says why. The events are still recorded.
Deciding
A common pattern is three bands on a noul signal:
noul | Action |
|---|---|
>= 0.9 | Block |
0.6 – 0.9 | Hold for human review |
< 0.6 | Publish |
Tune the thresholds on your own traffic: read a sample of answers from the console before you enforce them.
Failure handling
The request blocks on the analyzer, so give it a timeout suited to your latency budget and decide what happens when it fails:
402means the balance is empty; the events were recorded but not scored.502means the analyzer failed; the events were recorded.- A timeout or network error on your side means you don't know. Failing open (publish, then review asynchronously) or closed (hold) is a product decision.
Synchronous scoring is billed like any analysis and does not schedule another asynchronous one.