Skip to main content

Webhooks

How to receive score updates and new alerts from Prewave by webhook: setup, delivery behaviour, signature check and payloads.

Prewave sends an HTTPS POST to an address you choose. There are two events. The same delivery can arrive more than once, so keep the event id and skip one you have already processed.

Console

Create request type

Delivery type and X-Prewave-Event-Type

Score update

SCORE_UPDATE

score.changed

Alert created

ALERT_CREATED

alert.created

schemaVersion on a delivery is 1. Hold a delivery whose version you do not recognise.

Open Webhooks

Open your profile, then Active sessions. Webhooks is next to Manage API Tokens.
​

Connect an API key

Paste an API key and choose Connect. That key is the user the subscription belongs to. Scores and alerts are sent for that user. Another API key is a different user and has its own subscriptions.

Each API key can have one score subscription and one alert subscription. A second subscription for the same event returns 409 Conflict, even when the address is different. The two events can share one address.


​

Create a subscription

Choose Subscribe. A hint next to a field explains what it does. Every subscription needs:

  • URL. An absolute https address that is reachable from the public internet. localhost, private, and link-local addresses are rejected.

  • HMAC signing secret. A password you create, at least 16 characters. You can generate one and copy it. Prewave signs each call with it. It is not shown again after you save.

  • Event. Score update or Alert created. The extra fields depend on that choice.

Headers are optional. Each row is a name and a value, sent on every call. If your system only accepts a call that includes a client id and client secret, put those values here, using the header names your system expects. Names are case-insensitive. A blank value or a line break is rejected.

These header names are rejected: Content-Type, Host, Content-Length, Transfer-Encoding, Connection, X-Prewave-Event-Id, X-Prewave-Event-Type, X-Prewave-Timestamp, X-Prewave-Signature, X-Prewave-Signature-Version.

A perspective is the scoring view you already use in Prewave. The console lists the perspectives and collections that API key can access, so you pick them by name. The number in parentheses after a collection name is how many suppliers are in it.

A subscription cannot be changed. Delete it and create another to use a new address, secret, header, collection, perspective, or interval.

Viewing subscriptions requires access_public_webhooks. Creating and deleting them requires manage_public_webhooks.
​

Score update fields

  • Also send existing scores. Sends the scores that already exist, then later changes.

  • All supplier sites this API key can access. Sends every supplier site that key can access. No collection is selected. This option exists only for score updates.

  • Collection. Required, unless you chose all supplier sites.

  • Perspective. Required.

  • Interval. How often scores are recalculated: Every 6 hours, Every 12 hours, Once a day, or Once a week. Once a week is the default. A later call is sent only when the public score changed. An unchanged score is not sent again.

Alert created fields

  • Also send existing alerts. Sends the alerts that already exist in the collection, then new ones.

  • Collection. Required. New alerts are sent for the suppliers in this collection.

  • Perspective. Required.

A later change to an alert you already received is not sent as another call.
​


​

Look at a subscription

Open a row to see the address, collection, perspective, interval for a score subscription, the latest delivery, and the subscription id. Deliveries opens the calls for that subscription. Unsubscribe deletes it.
​

What your system should do

Accept the POST, store the event id, and answer before you do slower work. Prewave waits 5 seconds for the connection to open and 30 seconds for your answer. The body of your answer is ignored. Answer on the address you registered. Redirects are not followed, and a redirect is tried again.

The same delivery can arrive more than once, including after you already answered with success. Skip an event id you have already stored. For an alert, that event id is not the alert id. The alert id is inside the body. A new alert is a new event id.

Your answer

What happens

Success (2xx)

Marked delivered.

Busy or unavailable (408, 429, 5xx, or no answer in time)

Tried again.

A redirect (3xx)

Tried again. The new address is not called.

Any other client error (4xx)

Stopped. No further tries.

A delivery that is tried again is attempted up to 8 times. After each retryable failure Prewave waits 1 minute, then 5 minutes, 15 minutes, 1 hour, 4 hours, 12 hours, 24 hours, and 24 hours. After the last try it stops.

In the console, open a subscription and choose Deliveries.

Status

Meaning

Pending

Waiting to be sent.

Sending

The call is in progress.

Delivered

Your system answered with success.

Failed

The last try failed and another try is scheduled.

Stopped

Prewave will not try again.

Retry sends a failed or stopped delivery again. Send again repeats one that already succeeded. The payload in the details is the JSON your address received.


​

Check the signature

Every call, for both events, is signed with HMAC-SHA256. Compare it before you trust the body.

Header

Example

Content-Type

application/json

X-Prewave-Event-Id

67a30073-302a-4d0f-b416-720048582088

X-Prewave-Event-Type

score.changed or alert.created

X-Prewave-Timestamp

2026-10-20T14:37:27Z

X-Prewave-Signature

sha256=<hex>

X-Prewave-Signature-Version

1

X-Prewave-Signature is HMAC-SHA256 over the exact request body:

HMAC-SHA256(secret, "{epochSeconds}.{rawBody}")

epochSeconds is occurredAt as Unix seconds. rawBody is the body bytes as received. Verify those bytes. Parsing the JSON and writing it out again changes the signature. Compare the hex digest with the value after sha256=.

Score update

A call is sent when a supplier's public score changes. A score with no public value is not sent. payload.newScore is the score now. payload.oldScore is the previous public score when a later recalculation changes it. oldScore is null for the scores sent by Also send existing scores, and when there was no previous score.

The interval is how often Prewave recalculates. It is not how often an unchanged score is sent. Also send existing scores sends the scores that already exist, then later changes.

The console always sends a perspective, and either a collection or all supplier sites. On the API, a score subscription only starts that schedule when perspectiveId is set and either collectionId is set or includeAllSuppliers is true. Without those, the subscription is created and nothing is sent.

newScore and oldScore are the same public score object. groups, components, subComponents, and actionPriority appear when that breakdown is part of the export. Ignore a field you do not use. Null is a normal value.

Create it in the console, or with POST /public/v1/webhooks/subscriptions:

{
"type": "SCORE_UPDATE",
"url": "https://example.com/webhooks/prewave",
"signingSecret": "replace-with-a-long-secret",
"initialLoad": true,
"perspectiveId": 5484774,
"collectionId": 16716970,
"includeAllSuppliers": false,
"runInterval": "WEEKLY",
"customHeaders": {
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
}

includeAllSuppliers: true covers every accessible supplier site. Leave collectionId out in that case. runInterval is SIX_HOURS, TWELVE_HOURS, DAILY, or WEEKLY. It defaults to WEEKLY.

Prewave then sends:

{
"id": "67a30073-302a-4d0f-b416-720048582088",
"type": "score.changed",
"schemaVersion": 1,
"occurredAt": "2026-10-20T14:37:27Z",
"payload": {
"newScore": {
"targetId": 102006215,
"targetName": "Northwind Metals",
"edgeNumbers": [
{ "number": "ERP-12345", "source": "erp", "existingEdgeId": null }
],
"perspectiveId": 5484774,
"perspectiveName": "Default",
"calculatedAt": {
"date": "2026-10-20T14:37:27",
"_datetype_": "DateTime"
},
"score": 72,
"riskLevel": "Low"
},
"oldScore": {
"targetId": 102006215,
"targetName": "Northwind Metals",
"perspectiveId": 5484774,
"perspectiveName": "Default",
"calculatedAt": {
"date": "2026-10-13T14:37:27",
"_datetype_": "DateTime"
},
"score": 68,
"riskLevel": "Low"
}
}
}

Field

Meaning

id

This delivery. The same value as X-Prewave-Event-Id.

type

score.changed

occurredAt

When the score change was recorded.

payload.newScore

The public score now.

payload.oldScore

The previous public score, or null when there was none.

payload.newScore.targetId

Supplier site.

payload.newScore.targetName

Name of that site.

payload.newScore.edgeNumbers

Your supplier identifiers, when present. Each entry has number, an optional source, and an optional existingEdgeId.

payload.newScore.perspectiveId

Perspective the score was calculated for. perspectiveName is its name.

payload.newScore.calculatedAt.date

When the score was calculated. _datetype_ is DateTime.

payload.newScore.score

Prewave score. payload.oldScore.score is the previous one.

payload.newScore.riskLevel

Risk label. Can be null.

payload.newScore.actionPriority

value and riskLevel, when that breakdown is included.

payload.newScore.groups

Score groups. A group has groupId, name, score, riskLevel, and nested groups.

payload.newScore.components

A component has name, score, and riskLevel.

payload.newScore.subComponents

Same shape as a component.

Alert created

A call is sent when a new alert is created for a supplier in the collection. A later edit of that alert is not a new call.

payload is the same alert object as GET /public/v2/feed, with two differences. Geographic geo is not included. statusUpdates is included only when that data is enabled for your organization. The rest of the public feed is included, such as locations, media, labels, and links. Ignore a field you do not use.

Create it in the console, or with POST /public/v1/webhooks/subscriptions:

{
"type": "ALERT_CREATED",
"url": "https://example.com/webhooks/prewave",
"signingSecret": "replace-with-a-long-secret",
"collectionId": 16716970,
"initialLoad": true,
"perspectiveId": 5484774,
"customHeaders": {
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
}

collectionId is required. perspectiveId is required when initialLoad is true.

Prewave then sends:

{
"id": "8f1c2a40-6d2e-4b7a-9c11-0a5e3d7b91f2",
"type": "alert.created",
"schemaVersion": 1,
"occurredAt": "2026-10-20T15:04:11Z",
"payload": {
"id": 904122,
"uuid": "b7e1c0aa-1d44-4f2a-8a10-6c2d9e0b4417",
"title": "Flooding reported near Northwind Metals",
"createdAt": "2026-10-20T15:02:00Z",
"predictedAtStart": "2026-10-20T12:00:00Z",
"predictedAtEnd": null,
"description": "Local reporting describes flooding at the site.",
"active": true,
"event": { "uuid": "c31a9e20-77b4-4d1e-90aa-2f6b8d4e1103" },
"primaryTargets": [
{
"target": { "id": 102006215, "name": "Northwind Metals" },
"impactLevel": { "id": 3, "displayName": "High" }
}
],
"eventTypes": [
{ "id": 42, "value": "Flood", "svalue": "flood" }
],
"collectionPath": [
{ "id": 16716970, "name": "Tier 1 metals" }
]
}
}

Field

Meaning

id

This delivery. The same value as X-Prewave-Event-Id. This is not the alert id.

type

alert.created

occurredAt

When this delivery was created.

payload.id

The alert. payload.uuid is its uuid.

payload.title

What the alert says. description can also be null.

payload.createdAt

When Prewave created the alert.

payload.predictedAtStart

When the described event is expected to start. predictedAtEnd is when it is expected to end. Either can be null.

payload.event.uuid

Groups alerts about the same real-world event.

payload.active

Whether the alert is still active at the time it was sent.

payload.primaryTargets

Sites affected by the alert. Each entry has the site (target), an impact level, and optional priority.

payload.mentionedTargets

Sites mentioned in the alert.

payload.eventTypes

What kind of event it is. value is the display name. svalue is the stable name, such as flood.

payload.collectionPath

Collections this alert belongs to. Each entry has id, name, and the parent path.

Manage subscriptions with the API

The console calls these routes with the API key you pasted. You can call them yourself.

Method

Path

Permission

GET

/public/v1/webhooks/subscriptions

access_public_webhooks

GET

/public/v1/webhooks/subscriptions/{id}

access_public_webhooks

POST

/public/v1/webhooks/subscriptions

manage_public_webhooks

DELETE

/public/v1/webhooks/subscriptions/{id}

manage_public_webhooks

The list is paged. page starts at 0. size defaults to 100. Results are newest first.

Create returns 201 Created and a Location header for the new subscription. The response, for every read and for create, is only:

{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"url": "https://example.com/webhooks/prewave",
"eventType": "SCORE_UPDATE",
"createdAt": "2026-10-20T14:37:27Z"
}

The signing secret, headers, collection, perspective, interval, and initial-load choice are not returned. Keep them when you create the subscription.

Status

Meaning

400 Bad Request

The body, the address, or a header is not valid.

404 Not Found

That subscription does not exist for this API key.

409 Conflict

This API key already has a subscription for that event.

Did this answer your question?