Webhooks
Slipcase can send real-time notifications to your application when new articles are published. Instead of polling the API, your application receives an HTTP POST request for each matching article as it happens.
How it works
Section titled “How it works”- A Slipcase administrator configures a webhook subscription for your organisation, including content filters and your endpoint URL.
- When an article is published that matches your filters, Slipcase sends an HTTP
POSTto your endpoint. - Each request is signed with HMAC-SHA256 so you can verify it came from Slipcase.
Events
Section titled “Events”| Event | Description |
|---|---|
article.published | Fired when a new article matching your filters is published |
More event types may be added in the future.
Request format
Section titled “Request format”Each webhook is an HTTP POST with Content-Type: application/json. The body is a single article object:
{ "id": 123456, "heading": "Example article headline", "excerpt": "A brief introduction to the article content...", "body": "<p>Full article body in HTML.</p>", "featured_image": "https://assets.slipcase.com/image/abc123", "additional_images": [ "https://assets.slipcase.com/image/def456" ], "date": "2026-04-17", "url": "https://www.slipcase.com/article/example-article-headline", "article_type": "article", "article_format": 2, "topics": ["Insurance", "Reinsurance"], "organisation_logo_url": "https://assets.slipcase.com/logo/org123", "organisation_name": "Example Publisher", "external_url": "https://www.example.com/original-article", "paywalled": false, "registration_required": false}See Article Object — Push API payload for the full attribute reference.
Request headers
Section titled “Request headers”Every webhook request includes the following headers:
| Header | Description |
|---|---|
X-Slipcase-Signature | HMAC-SHA256 signature for verifying authenticity |
X-Slipcase-Timestamp | Unix timestamp (seconds) when the request was signed |
X-Slipcase-Delivery-Id | Unique UUID for this delivery attempt |
X-Slipcase-Event | Event type (e.g. article.published) |
Content-Type | application/json |
Verifying signatures
Section titled “Verifying signatures”Every webhook is signed using your subscription’s signing secret (provided by your Slipcase administrator). You should always verify the signature before processing a webhook.
The signature is computed as:
HMAC-SHA256( timestamp + "." + raw_body, signing_secret )Step-by-step
Section titled “Step-by-step”- Extract
X-Slipcase-TimestampandX-Slipcase-Signaturefrom the request headers. - Strip the
sha256=prefix from the signature header. - Concatenate the timestamp, a literal
., and the raw request body. - Compute the HMAC-SHA256 hex digest using your signing secret.
- Compare your computed signature with the one from the header using a timing-safe comparison.
PHP example
Section titled “PHP example”$timestamp = $_SERVER['HTTP_X_SLIPCASE_TIMESTAMP'];$signature = str_replace('sha256=', '', $_SERVER['HTTP_X_SLIPCASE_SIGNATURE']);$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $timestamp . '.' . $body, $signingSecret);
if (!hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature');}Node.js example
Section titled “Node.js example”const crypto = require('crypto');
const timestamp = req.headers['x-slipcase-timestamp'];const signature = req.headers['x-slipcase-signature'].replace('sha256=', '');const body = req.rawBody; // raw request body as string
const expected = crypto .createHmac('sha256', signingSecret) .update(`${timestamp}.${body}`) .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) { res.status(401).send('Invalid signature'); return;}Python example
Section titled “Python example”import hmacimport hashlib
timestamp = request.headers['X-Slipcase-Timestamp']signature = request.headers['X-Slipcase-Signature'].replace('sha256=', '')body = request.get_data(as_text=True)
expected = hmac.new( signing_secret.encode(), f'{timestamp}.{body}'.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature): abort(401, 'Invalid signature')Replay prevention
Section titled “Replay prevention”To prevent replay attacks, validate that the X-Slipcase-Timestamp is recent:
$timestamp = (int) $_SERVER['HTTP_X_SLIPCASE_TIMESTAMP'];if (abs(time() - $timestamp) > 300) { // 5-minute tolerance http_response_code(401); exit('Timestamp too old');}The timestamp is part of the HMAC input, so it cannot be tampered with without invalidating the signature.
Idempotency
Section titled “Idempotency”Each delivery includes a unique X-Slipcase-Delivery-Id. If your endpoint receives the same delivery ID more than once, you should treat subsequent deliveries as duplicates and skip processing.
Store processed delivery IDs (e.g. in a database or cache) and check before processing:
if ($this->alreadyProcessed($deliveryId)) { http_response_code(200); exit;}Retry behaviour
Section titled “Retry behaviour”If your endpoint returns a non-2xx status code or fails to respond, the delivery will be retried automatically with exponential backoff. After all retry attempts are exhausted, the delivery is sent to a dead-letter queue for investigation.
Best practices
Section titled “Best practices”- Respond fast — return
200 OKimmediately, then process asynchronously - Verify signatures — always validate
X-Slipcase-Signaturebefore trusting the payload - Check timestamps — reject requests older than 5 minutes
- Handle duplicates — use
X-Slipcase-Delivery-Idfor idempotency - Use HTTPS — your endpoint must be accessible over HTTPS
Webhook subscriptions are configured by a Slipcase administrator. Contact your account manager to provide:
- Your endpoint URL (must be HTTPS)
- Any content filter preferences (topics, companies, article types, etc.)
You will receive a signing secret to verify incoming webhooks.