ce-webhooks
4
总安装量
4
周安装量
#48876
全站排名
安装命令
npx skills add https://github.com/commercengine/skills --skill ce-webhooks
Agent 安装分布
opencode
4
gemini-cli
4
claude-code
4
github-copilot
4
codex
4
kimi-cli
4
Skill 文档
Webhooks & Events
Prerequisite: Webhooks are asynchronous. Use for background tasks (sync, notifications), not synchronous flows.
Quick Reference
| Task | Action |
|---|---|
| 1. Create endpoint | /api/webhooks/ce route in your app |
| 2. Verify signature | Validate webhook signature header |
| 3. Process event | Route by event_type, queue heavy work |
| 4. Return 200 | Respond quickly to acknowledge receipt |
Supported Events (14 Types)
| Category | Events |
|---|---|
| Order | order.created, order.confirmed, order.completed, order.cancelled |
| Payment | payment.success, payment.failed, payment.retried |
| Refund | payment.refund.initiated, payment.refund.success, payment.refund.failed |
| Shipment | shipment.created, shipment.updated, shipment.delivered, shipment.cancelled |
Decision Tree
Webhook Event Received
â
ââ Verify signature â Invalid? â Return 401
â
ââ order.created â Create order record in DB
ââ order.confirmed â Update order status, send confirmation email
ââ order.completed â Mark order as fulfilled
ââ order.cancelled â Update status, process refund logic
â
ââ payment.success â Mark order as paid
ââ payment.failed â Notify customer, update status
ââ payment.retried â Log retry attempt, update payment status
â
ââ payment.refund.initiated â Log refund request
ââ payment.refund.success â Update order, notify customer of refund
ââ payment.refund.failed â Alert team, log failure
â
ââ shipment.created â Log shipment, generate tracking
ââ shipment.updated â Update tracking info, notify customer
ââ shipment.delivered â Update status, trigger review prompt
ââ shipment.cancelled â Handle cancelled shipment
Key Patterns
Webhook Endpoint (Next.js App Router)
// app/api/webhooks/ce/route.ts
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";
export async function POST(req: NextRequest) {
const body = await req.text();
const signature = req.headers.get("x-webhook-signature");
// 1. Verify signature
if (!verifyWebhookSignature(body, signature)) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
const event = JSON.parse(body);
// 2. Route by event type
switch (event.event_type) {
case "order.created":
await handleOrderCreated(event.data);
break;
case "order.confirmed":
await handleOrderConfirmed(event.data);
break;
case "order.completed":
await handleOrderCompleted(event.data);
break;
case "payment.success":
await handlePaymentSuccess(event.data);
break;
case "payment.failed":
await handlePaymentFailed(event.data);
break;
case "payment.refund.success":
await handleRefundSuccess(event.data);
break;
case "shipment.delivered":
await handleShipmentDelivered(event.data);
break;
// ... handle other events
default:
console.log(`Unhandled event: ${event.event_type}`);
}
// 3. Return 200 quickly
return NextResponse.json({ received: true }, { status: 200 });
}
Webhook Endpoint (Express)
import express from "express";
import crypto from "crypto";
app.post("/webhooks/ce", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-webhook-signature"];
if (!verifyWebhookSignature(req.body, signature)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body.toString());
// Queue async work â return 200 immediately
queueWebhookProcessing(event);
res.status(200).json({ received: true });
});
Signature Verification
function verifyWebhookSignature(
body: string,
signature: string | null
): boolean {
if (!signature) return false;
const secret = process.env.CE_WEBHOOK_SECRET!;
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
Async Processing Pattern
// Return 200 immediately, process in background
async function handleOrderCreated(data: any) {
// For quick operations, handle inline:
await db.orders.upsert({
where: { order_number: data.order_number },
update: { status: data.status },
create: { order_number: data.order_number, ...data },
});
// For heavy operations, queue:
await queue.enqueue("send-order-confirmation", {
order_number: data.order_number,
user_email: data.customer_email,
});
}
When to Use Webhooks
Do use when:
- Syncing order data to your database
- Sending notifications (email, SMS, push)
- Triggering fulfillment workflows
- Updating inventory in external systems
- Analytics and reporting pipelines
Don’t use when:
- Need immediate response (use API polling instead)
- Building real-time UI updates (use SDK events or polling)
- Need guaranteed ordering (webhooks may arrive out of order)
Common Pitfalls
| Level | Issue | Solution |
|---|---|---|
| CRITICAL | No signature verification | Always verify x-webhook-signature before processing |
| CRITICAL | Webhook route requires auth | Make webhook route public â exclude from auth middleware |
| HIGH | Handler timeout | Return 200 immediately, queue heavy work for background processing |
| HIGH | Missing idempotency | Use event.id or order_number as idempotency key â webhooks may be retried |
| MEDIUM | Handling only one event | Subscribe to all relevant events (created, confirmed, cancelled, etc.) |
| MEDIUM | Exposing webhook secret | Store CE_WEBHOOK_SECRET in environment variables, never commit to code |
Webhook Reliability
- Retries: Failed deliveries (non-2xx response) are retried with exponential backoff
- Ordering: Events may arrive out of order â use timestamps to resolve conflicts
- Idempotency: Same event may be delivered multiple times â design handlers to be idempotent
See Also
orders/– Order data structure and APIsetup/– Environment variable configuration
Documentation
- LLM Reference (Webhooks): https://llm-docs.commercengine.io/webhooks/
- Node.js Integration: https://www.commercengine.io/docs/sdk/nodejs-integration
- AI Prompts (Webhook Handler): https://www.commercengine.io/docs/ai/prompts