Skip to content

Webhooks

Corso webhooks send real-time notifications to your systems when important events occur—such as when a claim or shipping protection claim is created or finalized. You configure an endpoint URL in Corso, and Corso sends an HTTP POST request to that URL whenever a subscribed event happens. This lets you sync claims to your CRM, trigger internal workflows, update reporting, or integrate with other tools without polling.


By setting up webhooks in Corso, you’ll be able to:

  • Receive instant notifications when claims or shipping protection claims are created or finalized
  • Keep external systems in sync with Corso using the full claim payload
  • Verify each request using HMAC-SHA256 signatures and your webhook secret
  • Rely on automatic retries with exponential backoff if your endpoint is temporarily unavailable

TopicDescription
claim/createdFires when a new claim is created.
claim/updatedFires when a claim is updated (e.g. line items, status, or metadata).
claim/finalizedFires when a claim is finalized.
shipping_claim/createdFires when a new shipping protection claim is created.
shipping_claim/updatedFires when a shipping protection claim is updated.
shipping_claim/finalizedFires when a shipping protection claim is finalized.
registration/createdFires when a new product registration is created.

You can enable or disable each topic per webhook in the Corso admin.


Corso sends the same headers with every webhook request, regardless of topic:

HeaderDescription
Content-Typeapplication/json
X-Corso-Webhook-IdUnique delivery ID
X-Corso-Webhook-TimestampUnix timestamp (seconds); not included in HMAC signature; provided for optional replay attack prevention.
X-Corso-SignatureHMAC signature, e.g. sha256=<hex>.
X-Corso-Webhook-TopicEvent topic (e.g. claim/created).
X-Corso-Api-VersionAPI version string.
X-Corso-Store-IdCorso store ID.

Use these headers for routing, idempotency, and signature verification. The request body (below) is the event-specific resource.


The request body is the event-specific resource only (the claim resource or the shipping protection claim resource). Its shape depends on the topic; delivery id, topic, store id, and API version are in the request headers above.

Claim topics (claim/created, claim/updated, claim/finalized)

Section titled “Claim topics (claim/created, claim/updated, claim/finalized)”

The body is the full claim resource—claim ID, status, type, line items, shipments, customer info, fees, timestamps, and more. All claim topics use the same payload shape.

Full example (matches the Commerce API claim resource):

{
"claimId": 456789,
"storeId": 123,
"externalId": "1-123-1",
"currencyCode": "USD",
"claimType": "Return",
"status": "In_Progress",
"customerEmail": "[email protected]",
"customerName": "Jane Doe",
"customerAddress": {
"line1": "1901 W Madison St",
"city": "Chicago",
"stateOrProvinceCode": "IL",
"postalCode": "60612",
"countryCode": "USA"
},
"sourceOrder": {
"orderId": 14,
"sourceOrderId": "7425696170134",
"orderNumber": "1580",
"createdOn": "2024-01-18T00:29:30.552Z"
},
"claimLineItems": [
{
"claimLineItemId": 108,
"quantity": 1,
"amount": 49.99,
"requestedAmount": 49.99,
"reason": "Wrong Size",
"status": "Open",
"statusDetail": "Pending_Review",
"requestedResolutionMethod": "Refund",
"sourceLineItem": {
"lineItemId": 42,
"sourceLineItemId": "38921234567890",
"productId": "8234567890123",
"variantId": "40123456789012",
"sku": "SKU-ABC",
"name": "Classic Tee - Blue / M",
"quantity": 1
},
"isShopNow": false
}
],
"shipments": [],
"tags": [],
"isInstantExchange": false,
"feeAmountApplied": 0,
"exchangeOrderShippingAmountApplied": 0,
"returnShippingAmountApplied": 0,
"createdOn": "2024-01-20T14:45:00.000Z",
"updatedOn": "2024-01-20T14:45:00.000Z",
"finalizedOn": null
}

Shipping claim topics (shipping_claim/created, shipping_claim/updated, shipping_claim/finalized)

Section titled “Shipping claim topics (shipping_claim/created, shipping_claim/updated, shipping_claim/finalized)”

The body is the shipping protection claim resource—shipping claim ID, status, reason, resolution method, line items, customer info, and timestamps.

Full example (matches the Commerce API shipping protection claim resource):

{
"shippingClaimId": 456789,
"storeId": 123,
"status": "Open",
"reason": "Lost",
"customerEmail": "[email protected]",
"sourceOrder": {
"orderId": 14,
"sourceOrderId": "7425696170134",
"orderNumber": "1580",
"createdOn": "2024-01-18T00:29:30.552Z"
},
"claimLineItems": [
{
"claimLineItemId": 108,
"quantity": 1,
"sourceLineItem": {
"lineItemId": 42,
"sourceLineItemId": "38921234567890",
"productId": "8234567890123",
"variantId": "40123456789012",
"sku": "SKU-ABC",
"name": "Classic Tee - Blue / M",
"quantity": 1
}
}
],
"currencyCode": "USD",
"createdOn": "2024-01-20T14:45:00.000Z",
"finalizedOn": null
}

Registration topics (registration/created)

Section titled “Registration topics (registration/created)”

The body is the product registration resource—registration ID, customer info, channel, line items, custom fields, and timestamps.

Full example:

{
"registrationId": 789012,
"storeId": 123,
"externalId": "REG-1580-1",
"customerEmail": "[email protected]",
"customerName": "Jane Doe",
"channelName": "Online Store",
"sourceOrder": {
"sourceOrderId": "7425696170134",
"orderNumber": "1580"
},
"emailMarketingConsent": true,
"emailMarketingConsentCollectedOn": "2024-01-20T14:45:00.000Z",
"lineItems": [
{
"lineItemId": 42,
"sourceLineItemId": "38921234567890",
"productId": "8234567890123",
"variantId": "40123456789012",
"sku": "SKU-ABC",
"name": "Classic Tee - Blue / M",
"quantity": 1,
"imgUrl": "https://cdn.example.com/products/classic-tee.jpg"
}
],
"createdOn": "2024-01-20T14:45:00.000Z"
}

Follow these steps to add a webhook in Corso.

  1. In Corso Admin, go to Settings → Webhooks (under Webhook Configurations).
  2. Click the + (plus) button to add a new webhook.
  3. In the Create Webhook modal:
    • Enter a Name (e.g. “My CRM Sync”) so you can identify this webhook later.
    • Enter your Endpoint URL. This must be a valid HTTPS URL that accepts POST requests.
  4. Click Create.

After the webhook is created, expand it in the list to see the HMAC Secret. Copy and store this secret securely; you’ll need it to verify webhook signatures. Corso generates this secret automatically.


Corso signs each request with HMAC-SHA256 using your webhook’s HMAC secret. You should always verify the signature before processing the event.

  1. Read the raw request body (before parsing JSON) and the X-Corso-Signature header.
  2. Strip the sha256= prefix from the signature.
  3. Compute HMAC-SHA256(rawBody, secret) and compare with the signature using a constant-time comparison.

Node.js example:

const crypto = require("crypto");
function verifyWebhookSignature(req, secret) {
const rawBody = req.rawBody; // or req.body as string, before JSON parse
const signatureHeader = req.headers["x-corso-signature"];
const signature = signatureHeader.replace(/^sha256=/, "");
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex"),
);
}

Python example:

import hmac
import hashlib
def verify_webhook_signature(body_bytes, headers, secret):
signature_header = headers["x-corso-signature"]
signature = signature_header.replace("sha256=", "")
expected = hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)

The X-Corso-Webhook-Timestamp header is provided separately and can optionally be used to reject requests that are too old (e.g. more than 5 minutes) to limit replay attack windows.


  • Your endpoint should respond with a 2xx status code to acknowledge receipt. Any other status or a network/timeout error triggers a retry.
  • Corso retries failed deliveries up to 5 times with exponential backoff:
    • 1 minute, 5 minutes, 30 minutes, 2 hours, 24 hours after the previous attempt.
  • Each attempt has a 30-second timeout. If your processing takes longer, respond with 200 immediately and process asynchronously.

After 5 failed attempts, the delivery is marked as failed and no further retries are sent.


  • Always verify the signature using your HMAC secret before trusting the payload.
  • Respond with 200 quickly and process the event asynchronously to avoid timeouts and retries.
  • Use the webhook delivery ID (X-Corso-Webhook-Id) for idempotency so duplicate deliveries (e.g. from retries) don’t create duplicate side effects.
  • Validate the payload (e.g. topic, storeId) before processing.
  • Optionally check the timestamp and reject requests that are too old to reduce replay risk.

What happens if my endpoint returns an error or times out?
Corso will retry up to 5 times with exponential backoff (1 min, 5 min, 30 min, 2 hr, 24 hr). Each attempt has a 30-second timeout. After 5 failures, the delivery is marked failed and no more retries are sent.

Can I have multiple webhooks?
Yes. You can create multiple webhook configurations. Each can have its own endpoint URL, secret, and set of enabled events.

How do I rotate the HMAC secret?
Create a new webhook with the same endpoint and events, update your server to use the new secret, then delete the old webhook once traffic has moved over.

What events are supported?
Corso supports claim/created, claim/finalized, shipping_claim/created, and shipping_claim/finalized. Additional topics may be added in future releases.