Webhook Guide
Webhooks let Plutto push events to your server as they happen, instead of you
polling the API. You configure one or more endpoints for your organization,
subscribe each to the events you care about, and Plutto delivers a signed
POST request every time a matching event fires.
How it works
- You create a webhook endpoint (a URL) in your Plutto dashboard and choose
which events it should receive. - When something happens (a validation finishes, an information request is
completed, etc.), Plutto fans the event out to every enabled endpoint
subscribed to that event type. - Each delivery is recorded as an event with its own id and full attempt
history, retried automatically on failure, and redeliverable on demand.
Endpoints are configured once per organization and reused across all
validations — you do not pass a webhook URL on each request.
Setup
1. Create an endpoint
In the Plutto dashboard go to Settings → Webhooks → Add webhook and set:
| Field | Description |
|---|---|
| Name | A label to identify the endpoint (e.g. Production). |
| URL | The HTTPS URL that will receive the events. |
| Subscribed events | The event types this endpoint receives (see below). |
| Authentication type | None, Secret key, or OAuth (see Authentication). |
| Status | Enabled / disabled. A disabled endpoint receives nothing. |
You can create multiple endpoints (e.g. one per environment or per team), each
with its own URL, subscriptions, and authentication.
2. Authentication
Choose one authentication type per endpoint:
-
None — no auth header is sent. Only recommended for testing.
-
Secret key — generate a signing key from the endpoint screen. Plutto sends
it on every request as:Authorization: Bearer whsec_xxxxxxxxxxxxxxxxVerify this header on your side to confirm the request came from Plutto. The
key is shown only once at generation time and is not recoverable —
store it securely. -
OAuth (client credentials) — Plutto fetches a bearer token from your OAuth
provider (grant_type=client_credentials) and sends it as
Authorization: Bearer <token>, refreshing it automatically. OAuth must be
configured at the organization level first — contact support to set it up. An
endpoint using OAuth cannot be enabled until OAuth is configured.
All endpoint URLs must be HTTP(S); HTTPS is strongly recommended in production.
3. Inspect endpoints via API (optional)
Your endpoints can be listed programmatically:
GET /api/v2/webhook_endpoints{
"webhook_endpoints": [
{
"id": "whe_5a6141dec2bc384e",
"name": "Production",
"url": "https://your-server.com/webhooks",
"enabled": true,
"subscribed_events": [
"data_source_run_batch.ready",
"information_request.all_items_collected"
],
"auth_type": "secret",
"created_at": "2026-07-01T12:00:00.000Z",
"updated_at": "2026-07-01T12:00:00.000Z"
}
]
}Creating, editing, and generating secrets is done from the dashboard, not the
public API.
The delivery envelope
Every webhook is a POST with Content-Type: application/json. Plutto wraps the
serialized resource in a small envelope:
{
"type": "data_source_run_batch.ready",
"data_source_run_batch": { ... }
}| Field | Description |
|---|---|
type | The event type that fired. |
| resource key | The serialized resource. The key depends on the event type (see next table). |
Resource key per event
The resource is nested under a key derived from the event type:
| Event type | Resource key |
|---|---|
entity_validation.stakeholder.created | stakeholder |
entity_validation.formation.ready | formation |
data_source_run_batch.ready | data_source_run_batch |
data_source_run_batch.consolidated_report_ready | data_source_run_batch |
data_source_run_batch.child_batches_ready | data_source_run_batch |
data_source_run_batch.data_source_run.ready | data_source_run |
information_request.all_items_collected | information_request |
information_request.analysis_success | information_request |
information_request.status_updated | information_request |
information_request.evaluated | information_request |
information_request.requestable_item.extracted | requestable_item |
information_request.assignment.updated | assignment |
Event Types
Subscribe an endpoint to any combination of the following.
Entity Validation Events
| Event | Trigger |
|---|---|
entity_validation.stakeholder.created | Stakeholders added to an entity validation |
entity_validation.formation.ready | The entity's societary (formation) information and legal report PDF are ready |
Data Source Run Batch Events
| Event | Trigger |
|---|---|
data_source_run_batch.ready | All runs of the main entity completed successfully |
data_source_run_batch.data_source_run.ready | An individual run completed |
data_source_run_batch.consolidated_report_ready | PDF report generated |
data_source_run_batch.child_batches_ready | The main entity's batch and every related entity (partner) batch finished |
Information Request Events
| Event | Trigger |
|---|---|
information_request.all_items_collected | All items submitted by recipient |
information_request.requestable_item.extracted | A single requestable item finished extraction |
information_request.assignment.updated | Reviewer assignment status changed |
information_request.status_updated | Status changed |
information_request.analysis_success | AI analysis completed |
information_request.evaluated | Responsible completed the after-evaluation flow (fires only when submitted) |
Payloads
All payloads below are shown with the full delivery envelope.
Entity Validation — stakeholder.created
stakeholder.created{
"type": "entity_validation.stakeholder.created",
"stakeholder": {
"id": "evl_e63adcdf5c702350",
"tin": "76613324-k",
"display_name": "Sociedad Comercial Bon Cas Limitada",
"name": "Sociedad Comercial Bon Cas Limitada",
"surname": "",
"category": "business",
"country": "CL",
"status": "created",
"created_at": "2026-02-02T15:51:12.105Z",
"information_requests": [
{
"id": "irq_bc8cf77370892cf1",
"name": "Nuevo cliente",
"created_at": "2026-02-02T15:51:12.188Z",
"recipient_url": "https://..."
}
],
"data_source_run_batches": [
{
"id": "dsrb_75eae47d0060cf5d",
"runs_succeeded": true,
"entity_validation_id": "evl_e63adcdf5c702350",
"information_request_id": "irq_bc8cf77370892cf1",
"execution_type": "direct",
"request_type": "normal",
"created_at": "2026-02-02T15:51:12.115Z",
"updated_at": "2026-02-02T15:54:34.166Z",
"consolidated_report_url": "https://..."
}
],
"related_entities": [
{
"id": "evl_557f33434aebd60e",
"tin": "20025804-5",
"country": "CL",
"display_name": "Alejandro Ignacio Castillo Valera",
"name": "Alejandro Ignacio",
"surname": "Castillo Valera",
"category": "person",
"risk_level": null
}
],
"latest_raised_alerts": [],
"latest_data_source_runs": [
{
"id": "dsr_c83d588a5c0bcc2f",
"type": "cl/bankruptcy_bulletins_search",
"entity_validation_id": "evl_e63adcdf5c702350",
"data_source_run_batch_id": "dsrb_75eae47d0060cf5d",
"created_at": "2026-02-02T15:51:12.127Z",
"succeeded_at": "2026-02-02T15:51:12.506Z",
"status": "succeeded",
"data": {
"id": "bbs_6bc2ce7c1f115d56",
"bankruptcy_bulletins": {
"count": 0,
"records_url": "/api/v2/data_source_runs/dsr_c83d588a5c0bcc2f/records"
}
}
}
]
}
}The
stakeholderobject contains the parent entity validation with its full
data, including the newly createdrelated_entities(the stakeholders that
were just added).
Entity Validation — formation.ready
formation.readyFired when the societary (formation) information of a business entity is complete and its
legal report PDF has been generated. Today this applies to entities incorporated in Chile's
Registro Electrónico de Empresas y Sociedades (RES/EUD), whose constitution is downloaded and
processed automatically. The event fires exactly once per validation (and once more on each
revalidation).
{
"type": "entity_validation.formation.ready",
"formation": {
"entity_validation_id": "evl_af478f4c2970c61c",
"data_source_run_batch_id": "dsrb_c7c342cfd44b8f2a",
"tin": "78486463-4",
"name": "PURO CORTE SPA",
"fantasy_name": null,
"country": "CL",
"source": "constitution",
"company_type": "spa",
"constitution_date": "2026-08-09T00:00:00Z",
"registry": "Registro Electrónico de Empresas y Sociedades",
"duration": "indefinida",
"activity_description": "la compra, venta, distribucion...",
"requires_manual_review": false,
"manual_review_codes": [],
"administration": {
"administration_type": "por un Gerente General",
"simple_signature": true
},
"equity": {
"total_amount": 500000,
"total_shares": 100,
"currency": "CLP",
"shares_type": "acciones nominativas, de una misma serie, ordinarias y sin valor nominal."
},
"stakeholders": [
{
"entity_validation_id": "evl_2819dd7a2a49c5c4",
"display_name": "Johander Juvenal Bitriaga Guzman",
"tin": "26423822-6",
"category": "person",
"roles": ["shareholder", "manager", "tax_representative"],
"ubo": true,
"participation": 1.0,
"shares": 100,
"amount": 500000,
"faculties": [
{ "key": "contratar cuentas corrientes", "code": "F001-GFB", "present": true },
{ "key": "garantizar obligaciones ajenas", "code": "F031-GGT", "present": false }
]
}
],
"documents": [
{
"id": "doc_2473f2946d76ea7e",
"name": "Escritura de constitución",
"label": "constitution",
"source": "RES",
"cve": "CR91crZ1tZRY",
"url": "https://...",
"created_at": "2026-08-19T15:43:45.685Z"
}
],
"legal_report_url": "https://..."
}
}
stakeholdersis the unified societary relation list:rolescome from the constitution
(shareholder,manager,general_manager,tax_representative,director),
participationis a 0–1 fraction, andfacultiesare the banking/legal powers detected for
managers.documentsare the source files (the constitution deed with its registrycve),
andlegal_report_urlpoints to the generated PDF. Document and report URLs are pre-signed
and expire after 24 hours — download them on receipt or re-fetch through the API.
Data Source Run Batch — ready
ready{
"type": "data_source_run_batch.ready",
"data_source_run_batch": {
"id": "dsrb_5a6141dec2bc384e",
"runs_succeeded": true,
"entity_validation_id": "evl_xxx",
"tin": "77092317-4",
"information_request_id": "irq_xxx",
"parent_batch_id": null,
"execution_type": "direct",
"request_type": "normal",
"created_at": "2026-07-01T19:48:18.056Z",
"updated_at": "2026-07-01T19:50:22.000Z",
"consolidated_report_url": "https://...",
"data_source_runs": [
{
"id": "dsr_xxx",
"type": "cl/tax_situation_search",
"status": "succeeded",
"created_at": "2026-07-01T19:48:18.056Z",
"succeeded_at": "2026-07-01T19:49:00.000Z"
}
],
"raised_alerts": [],
"child_batches": []
}
}Every batch object is self-similar: it carries its own tin, its own
raised_alerts, and its child_batches — one batch object per related entity
(partner), with the same shape. Alerts always belong to the batch that contains
them.
Child Batches Ready — Related Entity (Partner) Alerts
When Plutto validates a company, it also discovers and validates its related
entities (partners / UBOs). Those validations run asynchronously: they may
still be running when ready fires for the main entity.
data_source_run_batch.child_batches_ready fires once the main entity's batch
and all of its partner batches have completed. It is delivered exactly
once per validation, and it also fires when the entity has no partners — so you
can always treat it as the "everything, partners included, is done" signal.
child_batches_readyis gated by an organization-level setting. If you need it
and aren't receiving it, contact support to enable it for your organization.
Independently of that setting, the consolidated report is generated only once
the whole tree is ready, soconsolidated_report_readyreflects every partner
and fires after the tree completes (and afterchild_batches_readywhen enabled).
{
"type": "data_source_run_batch.child_batches_ready",
"data_source_run_batch": {
"id": "dsrb_5a6141dec2bc384e",
"runs_succeeded": true,
"entity_validation_id": "evl_main",
"tin": "77092317-4",
"parent_batch_id": null,
"execution_type": "direct",
"raised_alerts": [
{
"id": "rlal_xxx",
"name": "Causas legales en el último año",
"severity": "medium",
"entity_validation_id": "evl_main",
"data_source_run_batch_id": "dsrb_5a6141dec2bc384e"
}
],
"child_batches": [
{
"id": "dsrb_child1",
"runs_succeeded": true,
"entity_validation_id": "evl_partner1",
"tin": "12345678-9",
"parent_batch_id": "dsrb_5a6141dec2bc384e",
"execution_type": "related",
"raised_alerts": [
{
"id": "rlal_yyy",
"name": "Hallazgos listas Warning",
"severity": "high",
"entity_validation_id": "evl_partner1",
"data_source_run_batch_id": "dsrb_child1"
}
]
}
]
}
}To compile every alert of the validation, partners included:
const batch = payload.data_source_run_batch;
const allAlerts = batch.raised_alerts.concat(
batch.child_batches.flatMap((child) => child.raised_alerts)
);Good to know:
- Timing.
child_batches_readyfires once the last partner finishes (usually within
minutes of the main entity'sready).consolidated_report_readythen fires after
it, because the report is generated from the completed tree and includes every partner.
On the earlierreadyevent,child_batchesis already present but partners may show
runs_succeeded: falsewith partial alerts — a partner's alerts are final once its own
runs_succeededistrue. - Partner identity. Each child batch carries the partner's
tin. For full identity
(name, category, risk level), callGET /api/v2/entity_validations/:idon the main
entity —related_entities[]lists every partner. - Failure behavior. If a partner's data source fails definitively, neither this event
nor the automatic consolidated report is emitted for that validation (the report can
still be generated on demand). The rest of the core flow is never blocked by a partner.
Individual Data Source Run — data_source_run.ready
data_source_run.ready{
"type": "data_source_run_batch.data_source_run.ready",
"data_source_run": {
"id": "dsr_5ac79b8b3ecfaacf",
"type": "cl/tax_situation_search",
"entity_validation_id": "evl_xxx",
"data_source_run_batch_id": "dsrb_xxx",
"created_at": "2026-07-01T19:48:18.056Z",
"succeeded_at": "2026-07-01T19:49:00.000Z",
"status": "succeeded"
}
}Possible status values:
succeeded- Run completed successfullycreated- Run in progresstemporary_error- Temporary failure (will retry)definitive_error- Permanent failuremissing_input_data- Waiting for required input
Information Request — all_items_collected
all_items_collected{
"type": "information_request.all_items_collected",
"information_request": {
"id": "irq_5a6141dec2bc384e",
"name": "KYC Request",
"status": "pending",
"entity_validation_id": "evl_xxx",
"template_id": "irt_xxx",
"recipient_url": "https://...",
"consolidated_report_url": null,
"responsible_comment": null,
"requestable_items": ["..."],
"data_source_run_batch": {},
"assignments": ["..."]
}
}Full payload includes
requestable_items,data_source_run_batch,
assignments,information_sheet, andanalysis_chat. See the API reference
for the complete schema.
responsible_commentis included in every Information Request payload. It
remainsnulluntil the responsible reviewer submits the after-evaluation form
(typically delivered alongsideinformation_request.evaluated), and is exposed
at the payload root so consumers don't need to iterateassignments[].
Key resource fields
| Field | Description |
|---|---|
data_source_run_batch.id | Unique batch identifier |
runs_succeeded | Boolean indicating overall success |
entity_validation_id | Parent validation reference |
information_request_id | Associated request (if any) |
consolidated_report_url | PDF download URL when available |
data_source_runs | Array of individual results |
tin | Tax identification number of the batch's entity |
raised_alerts | Rule engine alerts of the batch's own entity |
child_batches | Related entity (partner) batches, each with its own tin, state and raised_alerts |
related_entities | Stakeholders linked to entity validation |
responsible_comment | Comment from responsible reviewer (Information Request, null until after-evaluation is submitted) |
Delivery, retries, and redelivery
- Retries. A delivery that doesn't get a
2xxresponse is retried up to
20 times with exponential backoff. A disabled endpoint fails immediately
without retrying. - Event status. Each delivery is tracked as an event with a status:
pending,succeeded,failed, orexpired. The full attempt history
(response code, body, duration, timestamp) is visible per event. - Redelivery. From Settings → Webhooks → (endpoint) → Event history you
can inspect any delivery and redeliver it manually — useful to replay an
event after fixing an outage on your side.
Best Practices
- Expect duplicates — retries and manual redeliveries can send the same
event again; make your handler idempotent. - Verify the
Authorizationheader — reject requests that don't carry your
endpoint's secret (or a valid OAuth token). - Respond with HTTP 200 quickly — acknowledge receipt, then process
asynchronously; don't block the response on your own work. - Store
data_source_run_batch.idto correlate related events. - Check
runs_succeededbefore processing results. - Subscribe to
child_batches_readyif your compliance decision depends on
the people behind the company — it is the only event that guarantees every
partner's alerts are final.
Event Flow
1. Entity Validation / Information Request created
|
+-- Data source runs start
| |
| +-- Individual runs complete
| | |
| | +-- data_source_run_batch.data_source_run.ready (per run)
| |
| +-- ALL runs of the MAIN entity complete
| | |
| | +-- data_source_run_batch.ready
| |
| +-- ALL runs of the main entity AND every partner complete
| |
| +-- data_source_run_batch.child_batches_ready
| |
| +-- Report generation starts (includes every partner)
| |
| +-- data_source_run_batch.consolidated_report_ready
|
+-- Stakeholders created (via societary data or API)
|
+-- entity_validation.stakeholder.createdAppendix — Legacy (V1) webhooks
Deprecated. The legacy model is being phased out as organizations migrate
to the endpoint-based model above. New integrations should use endpoints.
In the legacy model there are no organization-level endpoints. Instead you pass a
webhook_url on each resource you create, and Plutto delivers events to that URL:
POST /api/v2/entity_validations
{
"tin": "77092317-4",
"country": "CL",
"webhook_url": "https://your-server.com/webhooks",
"information_request": {
"template_id": "irt_xxx",
"webhook_url": "https://your-server.com/irq-webhook"
}
}Differences from the endpoint model:
- No subscriptions. The URL receives all events for that resource; you cannot
filter by event type. - Identifier. The configured URL is echoed back inside the resource as a
nestedwebhookobject (id=wbh_...,webhook_url,created_at); it is
nullwhen nowebhook_urlwas set. - Authentication. A single organization-wide Bearer token (configured via
support) is sent on all webhooks, rather than a per-endpoint secret.
{
"type": "data_source_run_batch.ready",
"data_source_run_batch": {
"id": "dsrb_5a6141dec2bc384e",
"runs_succeeded": true,
"webhook": {
"id": "wbh_xxx",
"webhook_url": "https://your-server.com/webhooks",
"created_at": "2024-01-15T19:48:18.056Z"
}
}
}