Green-Flag Pre-Publication Gate Webhook
16 min
overview by default, content goes live for your users immediately and is only pulled after the fact if proactive detection or a report identifies it as violating the green flag pre publication gate webhook flips that ordering nothing is shown to a user until nima has explicitly cleared the content when nima's moderation returns a green (passed) decision for a piece of content, nima immediately calls a webhook on your configured endpoint carrying that decision your platform holds the content back from users until it receives this signal (v3 1) one webhook, one endpoint per customer — nima does not route by policy or input label on its side filter or route the payload however you like on yours delivery is at least once — your endpoint should be idempotent see idempotency /#idempotency this is an entitlement add on and is off by default it's enabled per contract by your tremau/nima account team before your admin users can configure it companion event moderation failed if nima's ai provider can't moderate a piece of content at all (provider outage, timeout, etc ), you won't get a green decision — but you also won't get silence nima sends a moderation failed event on the same webhook, so you can fall back (e g route to manual review) instead of content getting stuck in limbo see the moderation failed section below whether to publish anyway (fail open) or hold for manual review (fail closed) on a moderation failed event is your call — nima notifies, it doesn't decide setting it up your account team first switches this feature on for your contract — it's off by default once entitled, your own admin users configure it directly in configure > api & integration > green flag webhook , with no engineering ticket to tremau required for day to day changes endpoint url — where nima sends post requests for both event types optional auth header — sent with every request if you need one (e g a bearer token on your side) signing secret — auto generated, used to verify requests came from nima see verifying deliveries /#verifying deliveries body template (optional) — customize the payload shape yourself see customizing the body /#customizing the body the enable/disable toggle saves automatically if you can't see the panel, ask your account team to confirm the entitlement, and check that your user has the relevant admin permissions the green event payload { "event" "green", "correlation id" "corr 12345", "content id" "content 67890", "case id" "case 4455", "reporter id" "rep 1", "reporter name" "jane doe", "reporter email" "jane\@example com", "reportee id" "ree 1", "reportee name" "john smith", "reportee email" "john\@example com", "content title" "player upload 882 png", "content type" "img", "content url" "https //example com/content/882 png", "content status" "cleared", "channel" "in game chat", "reason for request" "proactive scan", "priority" "normal", "ai status" "green", "provider" "sightengine", "decided at" "2026 07 24t15 44 58 299z", "customer specific" { " " "provider scores and base level request attributes" }, "content customer specific" { " " "content level attributes" } } customer specific probs and customer specific outcome are json strings, not nested objects — parse them if you need the underlying scores field reference field notes event always "green" for this notification type correlation id / content id together form the idempotency key see idempotency /#idempotency case id nima's internal case reference reporter id, reporter name, reporter email the reporting account that submitted the content, if applicable may be null reportee id, reportee name, reportee email the reported account the content belongs to may be null content title, content type, content url, content status content metadata content type matches your submitted content type ( img , video static , txt , etc ) channel, reason for request, priority context carried from the original submission channel is the source ai status, provider, decided at the decision itself and which ai provider made it customer specific, content customer specific your own custom attributes plus provider confidence scores, echoed back customizing the body if the default shape above doesn't fit your integration, set a body template in the settings panel yourself — no need to involve your account team for this templates use twig https //twig symfony com/doc/ , rendered against the same payload as above left empty, nima sends the default payload shown earlier the preview button in settings shows you exactly what would be delivered — it renders your template against a representative sample using the same engine and variable set nima uses at delivery time, so what you preview is what gets sent available variables 21 variables, all top level — the same fields as the payload above variable type notes correlation id, content id, case id string identifiers reporter id, reporter name, reporter email string may be null reportee id, reportee name, reportee email string may be null content title, content type, content url, content status string content metadata channel, reason for request, priority string submission context ai status, provider, decided at string the decision itself customer specific map base level attributes, including provider scores — see the gotcha below content customer specific map free form, content level attributes (keys vary by your setup) gotcha inside customer specific , the probs and outcome keys are json strings, not nested objects reaching into them with dot notation ( customer specific probs nudity ) returns nothing emit them with |raw instead {{ customer specific probs|raw }} {# → {"nudity" 0 02,"violence" 0 01} correct #} {{ customer specific probs|json encode }} {# → double encoded string — wrong #} sandbox templates render in a restricted twig sandbox allowed tags if , for , set allowed filters include json encode , raw , default , upper , lower , date , replace , trim , length , merge , and similar method call chains, attribute() , and self are blocked anything outside the allow list is rejected with an error when you try to save rule of thumb wrap every field in |json encode|raw — this keeps nulls valid and quoting correct { "id" {{ correlation id|json encode|raw }}, "content" { "id" {{ content id|json encode|raw }}, "title" {{ content title|default('untitled')|json encode|raw }}, "type" {{ content type|upper|json encode|raw }} }, "verdict" {{ ai status|json encode|raw }}, "scores" {{ customer specific probs|raw }}, "decided at" {{ decided at|json encode|raw }} } the template must render to a valid json object — this is checked when you save, and again on preview if a saved template ever fails to render at delivery time, nima silently falls back to the default payload rather than blocking delivery — a broken template never blocks the pre publication gate still, catch it with preview before saving the moderation failed event payload { "event" "moderation failed", "correlation id" "se fail corr 1", "content id" "se fail content 1", "reporter id" "rep 1", "reportee id" "ree 1", "content title" "stuck video", "content type" "video static", "content url" "https //example com/se/1 mp4", "provider" "sightengine", "error" "provider unavailable", "failed at" "2026 07 21t19 16 45 232z" } field reference field notes event always the literal "moderation failed" — use this to route it separately from "green" provider which ai provider failed (lower case id, e g "sightengine" ) error the provider's failure detail (falls back to a generic message if none is available) content type same shape as the green event nullable context fields reporter id , content title , etc may be null if not present on the original request a given piece of content will only ever produce one of green or moderation failed — never both timing if moderation fails synchronously, you're notified essentially immediately if it fails on a background/retry path, notification can take roughly 65–70 seconds — nima retries the provider a few times before giving up and telling you currently wired for one ai provider; more may be added over time without any change on your side verifying deliveries every request (both event types) is signed and carries header purpose x tremau signature sha256=\<hmac> — hmac sha256 of timestamp body , using your signing secret x tremau timestamp timestamp used in the signature — check it's recent to guard against replay idempotency key correlationid\ contentid use this to de duplicate — see idempotency /#idempotency (your configured auth header, if set) echoed as configured idempotency delivery is at least once, not exactly once — retries on nima's side mean your endpoint may occasionally see the same event twice use the idempotency key header (or correlation id + content id ) to dedupe on your end reliability & limits retries up to 10 attempts with exponential backoff (5s up to 60s) if your endpoint is unreachable or errors outage buffer if your endpoint is down, events are held for up to 3 hours before nima stops retrying that item this is a hard ceiling — alert on your side if your endpoint has extended downtime single endpoint one webhook endpoint per customer today; multiple endpoints aren't yet supported scope (v1) only green / moderation failed events are delivered this way amber/orange level outcomes aren't included unless you specifically use that gating — talk to your account team if you need it