Webhook Ingestion
Webhook ingestion is the simplest Data Ingest API entry point for external systems that can send a single JSON payload over HTTP. It is ideal for third-party products, automation tools, and lightweight integrations that do not need the full batched POST /api/ingest contract.
Endpoint
Each webhook connector posts to:
POST https://inspire.yourcompany.com/api/webhook/{stream}Example:
POST https://inspire.yourcompany.com/api/webhook/salesAuthentication
Authenticate with the connector’s data ingest credential:
Authorization: Bearer ik_<key_id>_<secret>Example:
curl -X POST https://inspire.yourcompany.com/api/webhook/sales \
-H "Authorization: Bearer ik_5f8d4c2a91be_pULjS4J8VbD2WXQYjM4f9m1i3p4lQ7mN1k2sT6uR" \
-H "Content-Type: application/json" \
-d '{
"region": "North",
"sales": 142000,
"target": 130000
}'Request model
The webhook API accepts one JSON object per request.
{
"region": "North",
"sales": 142000,
"target": 130000,
"updated": "2026-04-09T10:30:00Z"
}Current behavior:
- Top-level properties become DataPool fields.
- String, number, boolean, and null values are stored directly.
- Nested objects and arrays are stored as raw JSON strings.
- The item ID defaults to the
idproperty if present. - If no matching ID property exists, Inspire generates one automatically.
If you need batched writes, explicit item lists, or richer record shaping, use the full Data Ingestion API instead of the webhook surface.
Choosing the item ID
By default, Inspire looks for an id property in the payload.
To use a different property, pass idField in the query string:
curl -X POST "https://inspire.yourcompany.com/api/webhook/sales?idField=region" \
-H "Authorization: Bearer $INSPIRE_INGEST_KEY" \
-H "Content-Type: application/json" \
-d '{ "region": "North", "sales": 142000 }'That request will upsert the item keyed by region.
Signature Verification
When a connector has a Webhook Signing Key configured, Inspire requires every incoming request to carry a valid HMAC-SHA256 signature. This prevents forged payloads from being written to the DataPool.
Required headers
| Header | Format | Description |
|---|---|---|
X-Webhook-Signature | sha256=<hex> | HMAC-SHA256 of the raw request body, hex-encoded, prefixed with sha256= |
X-Webhook-Timestamp | Unix epoch seconds | Timestamp of the request. Must be within 5 minutes of the server’s clock to prevent replay attacks. |
Computing the signature
The signature is computed over the timestamp concatenated with the raw request body, using the connector’s webhook signing key as the HMAC key:
signature = HMAC-SHA256(key, timestamp + "." + body)Bash example
TIMESTAMP=$(date +%s)
BODY='{"region":"North","sales":142000}'
SIGNING_KEY="whsk_your_signing_key_here"
SIGNATURE=$(printf '%s.%s' "$TIMESTAMP" "$BODY" \
| openssl dgst -sha256 -hmac "$SIGNING_KEY" | awk '{print $2}')
curl -X POST "https://inspire.yourcompany.com/api/webhook/sales" \
-H "Authorization: Bearer $INSPIRE_INGEST_KEY" \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: sha256=$SIGNATURE" \
-H "X-Webhook-Timestamp: $TIMESTAMP" \
-d "$BODY"Node.js example
import { createHmac } from 'node:crypto'
const timestamp = Math.floor(Date.now() / 1000).toString()
const body = JSON.stringify({ region: 'North', sales: 142000 })
const signingKey = process.env.WEBHOOK_SIGNING_KEY
const signature = createHmac('sha256', signingKey)
.update(`${timestamp}.${body}`)
.digest('hex')
await fetch('https://inspire.yourcompany.com/api/webhook/sales', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INSPIRE_INGEST_KEY}`,
'Content-Type': 'application/json',
'X-Webhook-Signature': `sha256=${signature}`,
'X-Webhook-Timestamp': timestamp,
},
body,
})When no webhook signing key is configured on the connector, signature headers are ignored and requests are authenticated by the ingest key alone.
Response
Successful requests return 202 Accepted with a compact response body:
{
"status": "accepted",
"itemId": "North",
"fieldsUpdated": 2
}Typical statuses:
| Status | Meaning |
|---|---|
202 Accepted | Payload accepted and written |
400 Bad Request | Invalid or missing JSON body |
401 Unauthorized | Missing or invalid data ingest credential |
Example integrations
CI/CD pipeline
curl -X POST "$INSPIRE_WEBHOOK_URL?idField=build" \
-H "Authorization: Bearer $INSPIRE_INGEST_KEY" \
-H "Content-Type: application/json" \
-d "{
\"build\": \"$BUILD_NUMBER\",
\"status\": \"deployed\",
\"durationSeconds\": $BUILD_DURATION
}"Node.js
await fetch('https://inspire.yourcompany.com/api/webhook/app-metrics?idField=service', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INSPIRE_INGEST_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
service: 'api-gateway',
requestsPerMinute: 340,
errorRate: 0.02,
}),
})