Webhooks
Receive real-time notifications when events happen in your OverSkill workspace. Subscribe to events and get HTTP POST requests to your endpoint.
How Webhooks Work
- Create a webhook endpoint that can receive POST requests
- Register your endpoint URL with OverSkill via the API
- Select which events you want to receive
- When events occur, OverSkill sends a POST request to your endpoint
- Your endpoint returns a 2xx status to acknowledge receipt
💡 Tip
Use a service like webhook.site to test webhooks during development.
Payload Format
All webhook payloads follow this standard format:
{
"event": "app.created",
"timestamp": "2025-12-23T12:00:00Z",
"team_id": 123,
"data": {
// Event-specific data
}
}
Request Headers
| Header | Description |
|---|---|
Content-Type |
application/json |
X-Overskill-Event |
The event type (e.g., app.created) |
X-Overskill-Delivery |
Unique delivery ID (for deduplication) |
X-Overskill-Signature |
HMAC-SHA256 signature for verification |
X-Overskill-Timestamp |
Unix timestamp when request was sent |
Signature Verification
Verify webhook authenticity to ensure requests come from OverSkill:
Signature Format
X-Overskill-Signature: t=1703332800,v1=abc123def456...
Verification Steps
- Extract the timestamp (t) and signature (v1) from the header
- Compute expected signature:
HMAC-SHA256(timestamp + "." + request_body, signing_secret) - Compare your computed signature with the v1 value
- Optionally check timestamp is within acceptable window (e.g., 5 minutes)
Example (Node.js)
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const parts = signature.split(',');
const timestamp = parts[0].split('=')[1];
const receivedSig = parts[1].split('=')[1];
const signedPayload = `${timestamp}.${payload}`;
const expectedSig = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(receivedSig),
Buffer.from(expectedSig)
);
}
Example (Python)
import hmac
import hashlib
def verify_webhook(payload, signature, secret):
parts = dict(p.split('=') for p in signature.split(','))
timestamp = parts['t']
received_sig = parts['v1']
signed_payload = f"{timestamp}.{payload}"
expected_sig = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(received_sig, expected_sig)
Event Types
app.created
Triggered when a new app is created
Example Payload
{
"event": "app.created",
"timestamp": "2025-12-23T12:00:00Z",
"team_id": 123,
"data": {
"id": "abc123",
"name": "My App",
"status": "draft",
"created_at": "2025-12-23T12:00:00Z"
}
}
app.generation.completed
Triggered when app generation completes successfully
Example Payload
{
"event": "app.generation.completed",
"timestamp": "2025-12-23T12:05:00Z",
"team_id": 123,
"data": {
"app_id": "abc123",
"message_id": 456,
"status": "completed",
"preview_url": "https://preview-abc123.overskill.app"
}
}
app.deployment.completed
Triggered when deployment completes
Example Payload
{
"event": "app.deployment.completed",
"timestamp": "2025-12-23T12:10:00Z",
"team_id": 123,
"data": {
"app_id": "abc123",
"environment": "production",
"production_url": "https://abc123.overskill.app"
}
}
app.user.created
Triggered when a new user accesses an app
Example Payload
{
"event": "app.user.created",
"timestamp": "2025-12-23T12:15:00Z",
"team_id": 123,
"data": {
"id": 789,
"app_id": "abc123",
"user_email": "[email protected]",
"access_tier": "free"
}
}
Retry Policy
If your endpoint returns a non-2xx status or times out, we'll retry with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 8 hours |
⚠️ Important
After 5 failed attempts, the delivery is marked as failed. Ensure your endpoint responds within 30 seconds.
Best Practices
- ✓ Return 200 quickly - Process webhooks asynchronously. Acknowledge receipt immediately, then process the payload in a background job.
- ✓ Handle duplicates - Use the X-Overskill-Delivery header to deduplicate webhooks. Network issues may cause retries.
- ✓ Verify signatures - Always verify the X-Overskill-Signature header to ensure authenticity.
- ✓ Use HTTPS - Your webhook endpoint must use HTTPS. We don't send webhooks to HTTP endpoints.
- ✓ Monitor failures - Check the webhook deliveries API to monitor for failed deliveries.