Webhooks
Receive real-time notifications when events happen on your skills and account.
Overview
Webhooks allow you to receive HTTP POST requests to your server when specific events occur on Asterism. This enables you to build integrations, automate workflows, and react to events in real-time.
Tip: Webhooks are available on Pro plans and above.View pricing
Creating a Webhook
You can create webhooks via the API or through your dashboard.
Via Dashboard
- Go to Dashboard → Settings → Webhooks
- Click "Add Webhook"
- Enter your endpoint URL (must be HTTPS)
- Select the events you want to receive
- Click "Create Webhook"
Via API
curl -X POST https://api.joinasterism.com/v1/webhooks \
-H "Authorization: Bearer aster_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/ask",
"events": ["skill.published", "skill.downloaded"],
"secret": "your-webhook-secret"
}'Available Events
Subscribe to specific events to receive notifications when they occur.
skill.publishedTriggered when a new skill version is published
{
"event": "skill.published",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"skill": {
"id": "sk_xxx",
"name": "my-skill",
"fullName": "@username/my-skill",
"version": "1.2.0",
"description": "My awesome skill",
"securityScore": 95
},
"publisher": {
"id": "usr_xxx",
"username": "username"
}
}
}skill.downloadedTriggered when your skill is downloaded/installed
{
"event": "skill.downloaded",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"skill": {
"id": "sk_xxx",
"name": "my-skill",
"fullName": "@username/my-skill"
},
"client": "claude-code",
"downloadCount": 1542
}
}skill.starredTriggered when your skill receives a star
{
"event": "skill.starred",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"skill": {
"id": "sk_xxx",
"name": "my-skill",
"fullName": "@username/my-skill"
},
"user": {
"id": "usr_xxx",
"username": "fan"
},
"starCount": 89
}
}skill.review.createdTriggered when a new review is posted on your skill
{
"event": "skill.review.created",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"skill": {
"id": "sk_xxx",
"name": "my-skill"
},
"review": {
"id": "rev_xxx",
"rating": 5,
"title": "Great skill!",
"body": "This skill saved me hours..."
},
"reviewer": {
"username": "reviewer"
}
}
}skill.issue.createdTriggered when a new issue is opened on your skill
{
"event": "skill.issue.created",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"skill": {
"id": "sk_xxx",
"name": "my-skill"
},
"issue": {
"id": "iss_xxx",
"type": "bug",
"title": "Error when processing large files",
"body": "I'm getting an error..."
},
"author": {
"username": "reporter"
}
}
}user.followedTriggered when someone follows you
{
"event": "user.followed",
"timestamp": "2026-01-23T12:00:00Z",
"data": {
"follower": {
"id": "usr_xxx",
"username": "newfollower"
},
"followerCount": 156
}
}Verifying Webhook Signatures
All webhook requests include a signature header that you should verify to ensure the request came from Asterism.
Signature Header
Each request includes an X-Ask-Signature header containing an HMAC-SHA256 signature of the request body using your webhook secret.
Verification Example (Node.js)
import crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
// In your webhook handler
app.post('/webhooks/ask', (req, res) => {
const signature = req.headers['x-aster-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook
const event = req.body;
console.log('Received event:', event.event);
res.status(200).json({ received: true });
});Verification Example (Python)
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
# In your Flask handler
@app.route('/webhooks/ask', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Ask-Signature')
payload = request.get_data()
if not verify_webhook(payload, signature, os.environ['WEBHOOK_SECRET']):
return {'error': 'Invalid signature'}, 401
event = request.json
print(f"Received event: {event['event']}")
return {'received': True}, 200Best Practices
- ✓Respond quickly: Return a 2xx response within 5 seconds. Process events asynchronously if needed.
- ✓Handle duplicates: Webhooks may be retried. Use the event ID for idempotency.
- ✓Verify signatures: Always verify the webhook signature before processing.
- ✓Use HTTPS: Webhook endpoints must use HTTPS for security.
- ✓Monitor failures: Check the webhook delivery history in your dashboard.
Retry Policy
If your endpoint returns a non-2xx status code or times out, we will retry the delivery using exponential backoff:
- Attempt 1: Immediate
- Attempt 2: After 1 minute
- Attempt 3: After 5 minutes
- Attempt 4: After 30 minutes
- Attempt 5: After 2 hours
After 5 failed attempts, the webhook will be marked as failed. You can view delivery history and retry failed webhooks from your dashboard.
API Reference
/api/v1/webhooksList all your webhooks
/api/v1/webhooksCreate a new webhook
/api/v1/webhooks/:idGet webhook details with delivery history
/api/v1/webhooks/:idUpdate webhook URL or events
/api/v1/webhooks/:idDelete a webhook