skopik

Webhooks & Events

Session Webhooks allow your backend services to receive push notifications whenever an Agent Session progresses, requests human approval, or completes. Webhooks deliver streaming chunks and status transitions directly to your HTTP endpoints without maintaining persistent WebSockets.

Webhook subscriptions

Webhooks are scoped per environment (e.g. production or staging). When creating a subscription, provide the destination URL:

const result = await skopik.webhooks.create({
	environment: 'production',
	url: 'https://api.example.com/webhooks/skopik',
})

console.log('Subscription ID:', result.webhookSubscription.webhookSubscriptionId)
// Plaintext signing secret is returned ONLY upon creation
console.log('Signing Secret:', result.signingSecret)

Save the signingSecret in your application's secret store immediately. It is used to cryptographically verify that inbound HTTP requests originate from Skopik.

Event payload format

Skopik delivers events as JSON payloads under the session.chunks event structure:

{
  "event": "session.chunks",
  "environment": "production",
  "sessionId": "ses_98765",
  "agentId": "ag_12345",
  "cursor": "turn_3:seq_12",
  "timestamp": "2026-08-20T14:32:00.000Z",
  "chunks": [
    {
      "type": "message.chunk",
      "turn": 3,
      "seq": 12,
      "delta": "Security review completed: 0 high-severity issues found."
    },
    {
      "type": "session.status",
      "status": "idle",
      "waitingFor": null
    }
  ]
}

Common chunk types

Chunk Type When Emitted Key Fields
message.chunk Model streaming response tokens. delta, turn, seq
session.status Session transitions state. status, waitingFor
tool.call Agent initiates a tool invocation. tool, toolCallId, input
approval.requested Effectful operation paused for approval. operationId, name, input
approval.resolved An approval decision was recorded. operationId, decision

Verify webhook signatures

Every webhook POST request includes two security headers:

  • X-Skopik-Timestamp: Epoch timestamp in seconds when the webhook was dispatched.
  • X-Skopik-Signature: HMAC-SHA256 signature in hexadecimal format computed over ${timestamp}.${rawBody} using your subscription's signing secret.

Node.js verification example

import crypto from 'node:crypto'
import type { Request, Response } from 'express'

export function verifySkopikWebhook(
	rawBody: string | Buffer,
	signatureHeader: string,
	timestampHeader: string,
	signingSecret: string,
): boolean {
	const timestamp = Number.parseInt(timestampHeader, 10)
	const now = Math.floor(Date.now() / 1000)

	// Reject replays older than 5 minutes
	if (Math.abs(now - timestamp) > 300) {
		return false
	}

	const payload = `${timestampHeader}.${typeof rawBody === 'string' ? rawBody : rawBody.toString('utf8')}`
	const expectedSignature = crypto
		.createHmac('sha256', signingSecret)
		.update(payload)
		.digest('hex')

	return crypto.timingSafeEqual(
		Buffer.from(signatureHeader, 'hex'),
		Buffer.from(expectedSignature, 'hex'),
	)
}

// Express route handler example
app.post('/webhooks/skopik', express.raw({ type: 'application/json' }), (req: Request, res: Response) => {
	const signature = req.headers['x-skopik-signature'] as string
	const timestamp = req.headers['x-skopik-timestamp'] as string

	const isValid = verifySkopikWebhook(
		req.body,
		signature,
		timestamp,
		process.env.SKOPIK_WEBHOOK_SECRET!,
	)

	if (!isValid) {
		return res.status(401).send('Invalid signature')
	}

	const event = JSON.parse(req.body.toString('utf8'))
	console.log(`Received event for session ${event.sessionId}:`, event.chunks)

	res.status(200).json({ received: true })
})

Zero-downtime secret rotation

When rotating a webhook signing secret, Skopik generates a new secret while granting a transition grace period where signatures generated with either the old or new secret are accepted:

const { signingSecret } = await skopik.webhooks.rotateSecret('production')

// Update your receiver to accept the new secret
await secretStore.set('SKOPIK_WEBHOOK_SECRET', signingSecret)

Organization event log

For auditability, activity dashboards, and pull-based integrations, inspect the organization event log:

curl "https://api.skopik.com/api/v1/events?limit=50" \
  -H "Authorization: Bearer $SKOPIK_API_KEY"

The event log tracks all resource creation, updates, deletions, session runs, and administrative actions across your workspace.

API reference

SDK Method HTTP Endpoint Description
webhooks.list() GET /webhook_subscriptions List webhook subscriptions across environments.
webhooks.create() POST /webhook_subscriptions Create a webhook subscription for an environment.
webhooks.get() GET /webhook_subscriptions/{env} Read subscription details and secret version.
webhooks.rotateSecret() POST /webhook_subscriptions/{env}/rotate_secret Rotate the HMAC signing secret with grace period.
webhooks.delete() DELETE /webhook_subscriptions/{env} Delete a webhook subscription.