meta object with reviewer-safe context.
There are four webhook kinds:
profile_status_updatedis sent by Minerva screening and fires when a screening profile changes status, for example when findings appear or a reviewer decides.idvis sent by Minerva identity verification and fires as a session progresses; an artifact is captured, an assessment completes, or a reviewer decides.onboardingis sent by Minerva screening and fires when a combined screening and identity verification onboarding run changes state or completes.custom_list_deploymentis sent by Minerva custom lists and fires when a custom list deployment changes between pending, live, and down in a workspace where the list is active.
event.kind.
Configure webhooks
Create and manage destinations from the Developers page (Administration > Developers) in the Minerva dashboard. The API Keys page walks through the UI. Configuration is also available through the API athttps://api.gominerva.com/webhooks/v2/screening. Despite the screening in the path, it manages all four kinds: Create screening webhook.
Webhooks have a workspace or tenant scope. Workspace is the default. A workspace-scoped destination receives events from one workspace; a tenant-scoped destination receives events from every workspace in your organization, including workspaces you create later. An admin application key can manage both scopes.
Each destination holds a name, a destination URL, an event subscription list, and a webhook key. Each workspace can keep up to 10 destinations by default. Tenant-scoped destinations have a separate limit of the same size. Enterprise customers can request more.
The envelope
Every delivery uses the same envelope:webhookIdis the destination’s unique ID.webhookNameis the name you assigned, echoed back so you can route deliveries.tenantIdandworkspaceIdappear at the top level on every event kind. They name the organization and workspace where the event occurred, even when the destination has tenant scope. These are additive fields; ignore fields you do not recognize. The per-kindevent.metaobjects are unchanged.event.kindisprofile_status_updated,idv,onboarding, orcustom_list_deployment.event.valueis the specific event that fired (see the per-kind sections below).event.metacarries the event context. Its fields and value types differ per kind;idvdelivers every value as a string.
Workspace and tenant scope
Every destination record includesscope, either workspace or tenant. Omitting scope when creating a destination selects workspace. Workspace records include workspaceId; tenant records omit it, rather than returning null.
Access and workspace selection
Sendx-workspace-id to select the workspace for workspace-scoped destinations. Without it, a workspace-scoped key uses its own workspace; a tenant-scoped key uses your organization’s default workspace. The header never narrows the events received by a tenant-scoped destination. An x-workspace-id that does not name a workspace in your organization returns 404, and a value that is not a valid workspace ID returns 400.
Workspace-scoped and tenant-scoped keys created on the Developers page have no webhook permissions. With one of those keys, these endpoints return
403 with the message “Missing or insufficient permissions.” The message does not say that the key type is the problem. To manage destinations through the API, use a Live admin application key. You can also manage them on the Developers page.
Admin application keys are Live only. Tenant-scoped destinations must be enabled for your organization; creating or editing one before enablement returns 400.
Create, list, edit, and move destinations
Usehttps://api.gominerva.com/webhooks/v2/screening:
Moving a destination preserves its
id and webhookKey. To move it into a workspace, send scope: "workspace" and select the destination workspace with x-workspace-id. Moving in either direction requires a Live admin application key or a dashboard Owner/Admin. A move also checks the destination scope’s limit.
One receiver for all client workspaces
If you run one workspace per client, register a tenant-scoped destination once, before creating the client workspaces:cURL
workspaceId and validate the destination’s X-Webhook-Key.
A tenant destination and a workspace destination that subscribe to the same event at the same URL receive two logical deliveries. They have different webhook IDs and keys. Do not dedupe by URL or profile ID: use X-Webhook-Delivery-ID where supplied, as described in Delivery, retries, and dedupe.
For custom list deployment events, delivery-target changes can take up to 60 seconds to propagate because targets are cached. This is not a propagation guarantee for other event kinds.
Profile status updates (profile_status_updated)
Fires when a screening profile changes status. It also fires when a monitoring screening of a profile that is alreadypotential_match returns material matches: matches that alert suppression did not suppress and that are not already marked false positive. See When profile_status_updated fires. Subscribable values:
escalation and in_review are not subscribable: a profile moving into those states does not trigger a delivery of this kind.
The meta object for this kind:
The status that changed is
event.value; there is no status field in the
meta object for this kind. This kind’s meta also carries no tenantId.When profile_status_updated fires
A delivery is sent in three cases:- A screening changes the profile’s status, for example from
no_flagstopotential_match. - A screening of a profile that is already
potential_matchreturns material matches. This is usually a monitoring screening, and it also applies when the profile is onboarded again. The status stays the same, but the delivery tells you the latest screening still has material findings. Material matches are matches that repeated alert suppression did not suppress and that are not already marked false positive. With suppression off, every repeat of an open match is material. A monitoring screening with every match suppressed sends no delivery. - A reviewer or an API call updates the profile. This sends a delivery even when the status did not change.
meta fields are available on profile status deliveries and tell these cases apart:
Read
trigger together with searchId, not just event.value or the profile’s accumulated flags. A profile can stay potential_match and retain earlier flags when the latest screening has no material matches, because every match was suppressed or marked false positive. Its lastSearchId can advance while lastFlagSearchId still refers to an earlier screening. An onboarding delivery labeled status_change can also retain potential_match because a clean screening does not automatically clear an earlier flagged status. That delivery is not evidence of new material findings.
A rescreen delivery means the current screening has effective flags from material matches: the profile’s lastFlagSearchId identifies the same screening as searchId. It does not mean every match is new. To list what that screening found, see What changed since the last run.
- Ignore
metafields you do not recognize. Minerva adds fields to this object over time. - Dedupe on the
X-Webhook-Delivery-IDheader, which stays the same across retries of one delivery. See Delivery, retries, and dedupe.
Identity verification lifecycle (idv)
Fires as an IDV session moves through capture, assessment, and review. The IDV Integration Guide covers the full session lifecycle. Subscribable values:idv.document.capturedfires when a capture image or supporting document finishes uploading;meta.capturedKindnames the artifact kind, for exampleid_front.idv.session.completedfires when an assessment reaches a terminal state, alongside exactly one ofidv.session.approved,idv.session.failed, oridv.session.requires_review.idv.session.approvedfires when the session passed without a human decision (meta.reviewStatusisautomatic_pass) or a reviewer accepted it (meta.reviewStatusisaccepted).idv.session.requires_reviewfires when the assessment refused to auto-decide and a reviewer must look at it.idv.session.rejectedfires when a reviewer rejected the session. A model rejection never sends this value; it arrives asidv.session.requires_reviewinstead.idv.session.failedfires when the assessment itself failed.
automatic_passis a clean pass with no human review.requires_reviewmeans the service held the session for a human decision.escalationmeans a reviewer bumped it up while keeping it open.acceptedandrejectedare terminal human decisions.
meta object for this kind. All values are strings, so booleans arrive quoted ("true", not true):
Use
meta.sessionId, which is stable for the life of the session, to
correlate a session’s deliveries, and meta.externalId to join a delivery to
your own system’s reference for the profile. The onboarding webhook carries
externalId as well.Correlating events with sessions
Everyidv event for a session carries the same sessionId: it is the id returned by POST /sessions and used in GET /sessions/{sessionId}, and it does not change for the life of the session. When the session was created from a profile with an externalId, every event for the session carries it as well, mirroring the reference from your system.
Use sessionId to correlate a session’s events, and externalId to route them to your own customer record. Both are stable identifiers and safe to use as join keys; delivery retry and dedupe semantics are in Delivery, retries, and dedupe.
Profile onboarding (onboarding)
Fires for combined screening and identity verification onboarding runs. Subscribable values:profile_onboarding.review_requiredfires when the run needs review before it can complete, for example when screening findings appear or an IDV session is held for review.profile_onboarding.completedfires when the run finishes. Theoutcomefield says how:automatic_pass,accepted,rejected, orescalation.profile_onboarding.failedfires when the run failed.
meta object for this kind:
Example delivery:
A completed run is never reported while an enabled component is still pending,
and
review_required can arrive once per run. Deliveries are at-least-once
and can arrive out of order.Custom list deployments (custom_list_deployment)
Fires when a custom list’s deployment status changes, so your integration can stop polling the status endpoint after it publishes a version. The values use the same public status vocabulary as that endpoint, so a delivery’s status is what the status endpoint would have returned at that moment. Subscribable values:
This kind requires custom lists to be enabled for your organization. Creating a webhook with this kind, or changing its values, returns
400 with “Custom list webhooks require custom lists to be enabled for this organization. Contact support@gominerva.com to enable custom lists.” when they are not.
Minerva sends a delivery only when the status actually changes:
- A list that stays
livesends nothing more, however long it serves. - A list’s first deployment sends no
pending, because a new list is already pending. You receiveliveordownwhen the deployment finishes. - Archiving a list sends nothing, including when someone archives it from the dashboard. To detect that, read the list with
GET /{listId}.
meta object for this kind:
The
failure object never carries internal diagnostics. failure.stage is one of these values, each with a fixed failure.message:
Example delivery:
down delivery carries the failure summary:
Publishing one list briefly moves the organization’s other
live lists to
pending while Minerva redistributes them, then back to live. Each of those
lists sends a pending and then a live delivery with an unchanged
versionId. Treat them as expected, not as a new deployment.Delivery, retries, and dedupe
Every delivery is a JSON POST withContent-Type: application/json and the X-Webhook-Key header carrying the destination’s webhook key. Screening, onboarding, and custom list deployment kinds also send X-Webhook-Delivery-ID, an opaque ID that is stable for each delivery and destination, so a retry repeats it. It is a 64-character hexadecimal string.
Delivery is at-least-once. A delivery can be attempted more than once and deliveries can arrive out of order, so make your handler idempotent.
profile_status_updated, onboarding, and custom_list_deployment deliveries:
- Each dispatch makes up to 3 attempts in process (about 100 ms, then 300 ms between them), retrying on
408,429,502,503,504, and transport errors; a429response’sRetry-Afteris honored up to 3 seconds. - A delivery is attempted at most 6 times: 1 inline attempt plus durable retries after 5 minutes, 15 minutes, 45 minutes, 2 hours 15 minutes, and 6 hours 45 minutes, scheduled by a 5-minute sweeper.
- For
custom_list_deployment, a3xxresponse or any other4xxresponse, including401or403from a receiver that rejects the key, is permanent and is not retried. Redirects are never followed. A change that Minerva cannot start delivering within an hour is dropped rather than sent late; reconcile with the status endpoint if you suspect a missed delivery. - For
custom_list_deployment, a destination that resolves to a non-public address is refused. That failure is permanent and is not retried.
idv deliveries:
- Up to 6 attempts with waits of 30, 60, 120, 240, and 480 seconds.
- Transport errors and
5xxresponses are retried;3xxand4xxresponses are permanent rejections (redirects are never followed), and exhausted deliveries are dead-lettered.
2xx response and process it asynchronously. Anything else is treated as a failure and retried or dropped according to the schedule above. Keep the response body small: an idv delivery whose response body exceeds 64 KiB is aborted as a policy violation.
Dedupe guidance:
- For
profile_status_updated,onboarding, andcustom_list_deployment, dedupe onX-Webhook-Delivery-ID. - For
idv, there is no delivery ID on the wire. Dedupe on the natural event key (sessionId,event.value,occurredAt, pluscapturedKindforidv.document.captured) or make your handler idempotent.
Test a destination
The Admin API’s test endpoint sends a simulated payload to your destination URL so you can confirm the endpoint is reachable and your receiver validates the key. The test send carries only theX-Webhook-Key header and generates its payload server-side, so the mock structure mirrors production but the values are not a replay of a real event.
Security
- Validate
X-Webhook-Keyon every delivery and reject mismatches before processing the body. - Store the webhook key in a secrets manager, and rotate it by recreating the destination if it leaks.
- Destination URLs must be public HTTPS endpoints you control. For
idvandcustom_list_deploymentdeliveries, Minerva checks the destination and refuses loopback, private, link-local, and cloud metadata addresses;idvalso sends only to HTTPS endpoints. Screening and onboarding deliveries do not perform that address check, so hold their destinations to the same standard yourself. - Deliveries are designed to be reviewer-safe: payloads carry IDs, statuses, and counts, not document contents, OCR text, or raw model output. Treat the endpoint itself as sensitive anyway, because the fields are only safe in the context of your own workspace.