Using OverSkill API webhooks

Get pushed events for generations, deployments, and app users. Registration, the event catalog, signature verification, and testing deliveries.

Webhooks push events to your server the moment they happen — no polling. They're the recommended way to track generations and deployments in production integrations.

Registering a webhook

POST /api/v1/webhooks
X-API-Key: os_…
Content-Type: application/json

{
  "url": "https://yourapp.example.com/overskill",
  "name": "Production listener",
  "events": ["app.generation.completed", "app.generation.failed", "app.generation.blocked"],
  "secret": "a-strong-shared-secret-you-generate"
}

Always set a secret — it's what makes signature verification possible. Manage endpoints with GET /api/v1/webhooks, PATCH /api/v1/webhooks/{id}, and DELETE /api/v1/webhooks/{id}.

The event catalog

Generation (the ones most integrations need):

  • app.generation.started / app.generation.progress / app.generation.completed / app.generation.failed
  • app.generation.blocked — generation halted by a business rule (for example, the team is out of credits). The payload includes block_type, balance, and required_credits. Don't auto-retry a blocked generation — surface the block to your user (e.g. a top-up prompt) instead.

App lifecycle: app.created, app.updated, app.deleted

Deployments: app.deployment.started, app.deployment.completed, app.deployment.failed, app.rollback

App users: app.user.created, app.user.access_granted, app.user.access_revoked, app.user.access_restored, app.user.tier_upgraded, app.user.tier_downgraded

Team/billing: team.subscription.created, team.subscription.updated, team.subscription.cancelled

Knowledge base: rag.document.created, rag.document.indexed, rag.enabled

Domains: domain.verified

Testing: webhook.test

Verifying signatures

Every delivery carries an X-Overskill-Signature header:

X-Overskill-Signature: t=1753031000,v1=5f8a2c…
  • t is a Unix timestamp
  • v1 is HMAC-SHA256(secret, "{t}.{raw_request_body}") in hex

To verify: recompute the HMAC over the timestamp + a dot + the raw request body (before any JSON parsing), compare with a constant-time comparison, and reject deliveries whose timestamp is older than ~5 minutes (replay protection).

Node example:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(header, rawBody, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected); const b = Buffer.from(v1);
  return a.length === b.length && timingSafeEqual(a, b);
}

A complete runnable webhook server (Node, zero dependencies) ships in the OverSkill repo at docs/api-examples/node/webhook-server.mjs.

Testing and monitoring deliveries

  • POST /api/v1/webhooks/{id}/test — sends a webhook.test event to your endpoint right now
  • GET /api/v1/webhooks/{id}/deliveries — recent delivery attempts with status codes

Delivery behavior

  • Respond with a 2xx quickly (do your processing async). Non-2xx responses and timeouts are retried; 5xx responses trigger retry with backoff.
  • Deliveries can occasionally arrive more than once — make your handlers idempotent.

Prefer per-job callbacks?

If you only care about one generation at a time, you can skip endpoint registration entirely: pass callback_url (plus optional metadata for correlation) when you POST /api/v1/generation_queue, and status updates for that job POST straight to your URL.

Was this helpful?

Thanks for the signal — it helps us improve the docs.

More in Advanced

Using OverSkill from AI agents (Claude, Cursor, Codex)

OverSkill is built for AI agents to use. Here's how to wire up Claude, Cursor, Codex, or your own agent.

Working with multiple apps

Patterns for managing several apps at once — organization, naming, sharing components.

Getting started with the OverSkill partner API

Generate, manage, and deploy apps programmatically. Auth, the core call sequence, and working code in Node, Python, and curl.

Still need help?

If this didn't answer your question, our team is one click away.