Webhooks Guide
Receive real-time notifications when events happen in your storefront — queries, negotiations, transactions, and more.
How webhooks work
When an event occurs (e.g., a negotiation is accepted or a transaction is completed), Cresva sends an HTTP POST request to your configured endpoint with the event data as a JSON payload.
- Register a webhook endpoint in your dashboard
- Cresva sends a POST request with the event payload
- Your server verifies the HMAC signature
- Your server processes the event and returns a 2xx response
Setting up an endpoint
Navigate to Settings → Webhooks in the Cresva dashboard. Add a new endpoint with:
- URL: Your HTTPS endpoint (e.g.,
https://your-app.com/webhooks/cresva) - Events: Select which event types to subscribe to, or choose "All events"
- Secret: A webhook secret will be generated — save this for signature verification
Your endpoint must respond with a 200 status code within 30 seconds, or the delivery will be marked as failed.
Verifying signatures
Every webhook request includes an X-ACP-Signature header with an HMAC-SHA256 signature of the request body. Always verify this signature to ensure the webhook is authentic.
import crypto from "crypto";
function verifyWebhookSignature(rawBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf-8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
}
// Express.js example
app.post("/webhooks/cresva", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-acp-signature"];
const isValid = verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body);
console.log("Event received:", event.type);
// Process the event...
switch (event.type) {
case "transaction.completed":
handleTransactionCompleted(event.data);
break;
case "negotiation.accepted":
handleNegotiationAccepted(event.data);
break;
}
res.status(200).send("OK");
});Event payload format
Every webhook event has this structure:
{
"id": "evt_1234567890",
"type": "transaction.completed",
"created_at": "2026-03-27T10:30:00Z",
"data": {
"transaction_id": "txn_x9y8z7",
"status": "COMPLETED",
"total": 178.60,
"currency": "USD",
"items": [
{
"product_id": "prod_h7k2m",
"title": "ProSound ANC-300 Wireless Headphones",
"quantity": 1,
"price": 164.99
}
]
}
}Event types
Queries
query.completedquery.failedNegotiations
negotiation.initiatednegotiation.counterednegotiation.acceptednegotiation.rejectednegotiation.expirednegotiation.withdrawnTransactions
transaction.createdtransaction.confirmedtransaction.paidtransaction.fulfillingtransaction.completedtransaction.cancelledtransaction.disputedtransaction.resolvedEscrow
escrow.createdescrow.releasedescrow.disputedProducts
product.updatedproduct.out_of_stockproduct.back_in_stockPricing
price.changedOffers
offer.createdoffer.expiredoffer.claimedTrust
trust.updatedBundles
bundle.createdbundle.expiredFeedback
feedback.receivedRetry behavior
If your endpoint returns a non-2xx response or times out (30 seconds), Cresva retries with exponential backoff:
ImmediateFirst delivery attempt+1 minuteFirst retry+5 minutesSecond retry+30 minutesThird retry+2 hoursFourth retry+24 hoursFinal retryAfter 6 failed attempts, the endpoint is automatically disabled and an email notification is sent to the account owner. Re-enable it from the dashboard after fixing the issue.