Claim Status Webhook

Webhook endpoint documentation for claim status change notifications. This endpoint represents the structure of webhook payloads sent to your configured webhook URL when claim statuses change.

Webhook requests

Authentication and Processing

Webhooks sent from Extend require digital signature verification. Once verified, the webhooks can be processed for business logic.

  • The webhook payload is JSON.
  • The signature is sent as a signature header.
  • Extend's public key id is sent as the X-Extend-Key-Id header.
  • Extend's key id is also sent in the webhook request payload as kid. Confirm that the value of X-Extend-Key-Idand kid match.

As part of the verification flow, you will need to make an HTTP GET request to Extend's JWKS endpoint: https://api.helloextend.com/service-orders/oauth/keys.

Request

GET https://api.helloextend.com/service-orders/oauth/keys

Example Response

{
  "keys": [
    {
      "kty": "RSA",
      "alg": "RS256",
      "use": "sig",
      "key_ops": [
        "sign",
        "verify"
      ],
      "kid": "b35edb9f-4be9-4cb4-9425-6f3d04ac9347",
      "n": "tvFPcO-lSUcW9n_dv45wfY0yF47CXZLICqS5kWIypfpP2NX4WRDK8c0bXx6g9P4n_UjJqyDsa-ocMil2dWRDn2oGCzrZLvk6bwerQfCij0Qvy92YZAWJ8r2QrQN69LZzrzCqpMbleclb4du5L46tIdWpOuWx9JWOD_F_HROyd26-SIUvrsLnk7pjSsRx1Bp9mw-qjIB2tEFCINrD3IDcFicPKMpWImhNA-Bukq3ZySzq2VvqAqmhif5EsLw4XWXOucM7YWLn5MfscRippwky94emVD4Hc3LaIYdjxcSMd9Gyr4vgEQU-sgj_hrBfjCabLEsfELIbrC4aPaNN1VTar91ErycEtmH5fNAhI7ka1YUFt5-AgvXDcPs4vnHuTX86TG_0IMhSxr-jvdarYJbTdbLU2-ViRSjIc3FSg4qjvxmyfJNXkwIWHy5Mh3kEK3GA573GofyCTjo20IwjNwhys0PdMnC9YXJQATPE4BvADaaA4UiKDeMfpOXA4Y6dgA9HDRVoA0RgNAycfHh0eIyjnOZjaU7napAxQjr7xqTw_8d8_MpCdAaAb70iL5pbbAtXpuhB27fvKNgvQGD3-X6idEbMYuJmZHzqDMfEmJROd4SjQl0OR5Lay5KpZyvjVsskh0GEbU_HR87UYP8FJn-avDhG6jU-HtSDJahACXeaS-s",
      "e": "AQAB"
    }
  ]
}
  • Parse the JSON response which contains an array of keys in JWK format. Find the specific key that matches the kid from the webhook payload.
  • Convert the JWK (JSON Web Key) to PEM format, which is required for most signature verification libraries. This typically involves using a crypto library to create a public key object from the JWK and exporting it in PEM format. Here is an example using the cryptoNode module.
/**
 * Convert a JWK to PEM format
 *
 * @param jwk - The JWK object (the full key Object from the 'keys' array)
 * @returns PEM formatted key
 */
function jwkToPem(jwk: any): string {
  try {
    const publicKey = crypto.createPublicKey({
      key: jwk as unknown as NodeJsonWebKey,
      format: 'jwk',
    })
    return publicKey.export({ type: 'spki', format: 'pem' }).toString()
  } catch (error) {
    Log.error('Error converting JWK to PEM', error)
    throw error
  }
}

Verify the Digital Signature. Use a cryptographic library to verify that the signature was created using the private key corresponding to the public key. The verification should use the RSA-SHA256 algorithm. The signature is typically base64-encoded and needs to be decoded before verification.

import crypto from 'crypto'
/**
 * Returns true if signature verification passed
 *
 * @param body - Stringified body of the webhook
 * @param publicKey - Base64 encoded publicKey. 
 * @param signature - Base64 encoded signature. Found in webhook ['signature'] header.
 * The signature found in the request header is Base64 encoded.
 * @returns true if the verification passed
 */
function verifyDigitalSignature(
  body: string,
  publicKey: string,
  signature: string,
): boolean {
  try {
    return crypto.verify(
      'RSA-SHA256',
      Buffer.from(body),
      Buffer.from(publicKey, 'base64'),
      Buffer.from(signature, 'base64'),
    )
  } catch (e) {
    return false
  }
}

// Example usage
const publicKey = 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUF0dkZQY08rbFNVY1c5bi9kdjQ1dwpmWTB5RjQ3Q1haTElDcVM1a1dJeXBmcFAyTlg0V1JESzhjMGJYeDZnOVA0bi9VakpxeURzYStvY01pbDJkV1JECm4yb0dDenJaTHZrNmJ3ZXJRZkNpajBRdnk5MllaQVdKOHIyUXJRTjY5TFp6cnpDcXBNYmxlY2xiNGR1NUw0NnQKSWRXcE91V3g5SldPRC9GL0hST3lkMjYrU0lVdnJzTG5rN3BqU3NSeDFCcDltdytxaklCMnRFRkNJTnJEM0lEYwpGaWNQS01wV0ltaE5BK0J1a3EzWnlTenEyVnZxQXFtaGlmNUVzTHc0WFdYT3VjTTdZV0xuNU1mc2NSaXBwd2t5Cjk0ZW1WRDRIYzNMYUlZZGp4Y1NNZDlHeXI0dmdFUVUrc2dqL2hyQmZqQ2FiTEVzZkVMSWJyQzRhUGFOTjFWVGEKcjkxRXJ5Y0V0bUg1Zk5BaEk3a2ExWVVGdDUrQWd2WERjUHM0dm5IdVRYODZURy8wSU1oU3hyK2p2ZGFyWUpiVApkYkxVMitWaVJTakljM0ZTZzRxanZ4bXlmSk5Ya3dJV0h5NU1oM2tFSzNHQTU3M0dvZnlDVGpvMjBJd2pOd2h5CnMwUGRNbkM5WVhKUUFUUEU0QnZBRGFhQTRVaUtEZU1mcE9YQTRZNmRnQTlIRFJWb0EwUmdOQXljZkhoMGVJeWoKbk9aamFVN25hcEF4UWpyN3hxVHcvOGQ4L01wQ2RBYUFiNzBpTDVwYmJBdFhwdWhCMjdmdktOZ3ZRR0QzK1g2aQpkRWJNWXVKbVpIenFETWZFbUpST2Q0U2pRbDBPUjVMYXk1S3BaeXZqVnNza2gwR0ViVS9IUjg3VVlQOEZKbithCnZEaEc2alUrSHRTREphaEFDWGVhUytzQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==';

const requestBody = '{"serviceOrderId":"73752710-8cdf-4fe3-8327-6936fa3badd6","claimId":"7b67180d-0ae6-4d81-a0ca-d7eeda41870e","contractId":"770e5f9d-fb2d-4c53-9137-cbb647d037f5","servicerId":"26db19a3-d9db-4ad4-9575-b7ca2f6e990a","customerName":"Paul Name","customerEmail":"[email protected]","contractPurchaseDate":1655668093818,"customerShippingAddress":{"city":"San Francisco","address1":"533 Mission Street","provinceCode":"CA","countryCode":"USA","postalCode":"94105"},"customerPhoneNumber":"555-535-5555","productDetails":[{"productReferenceId":"PRODUCT-REPAIR-385UmuLNaUqVmpohrmnvMqrncttQCz","productListPrice":25199,"productPurchasePrice":25199}],"failureType":"webhook parse","failureDescription":"webhook","incident":{"failureType":"electricalFailure","description":"BROKE PLZ HALP","occurredAt":1695152893819,"FailureType":"webhook parse","FailureDescription":"webhook","productCondition":"nonfunctional"},"sendDate":1695152952396,"url":"https://webhook.site/70a09585-f934-4b01-855b-0869e5e19752","transactionId":"63815176-f685-44ca-8180-fb13e39d5d04","type":"assign"}';
const signature = 'JJbRyjmmylP4GJtNCT7wANYVMkmUYENuX13sXqMjbAUcfidBBix/hzCjnoycg6lCT1Ktny2OnmixEHQAwNFOuReTlid+AFvCQnQ0nA+aUjvD3JSYCLLE2SOuvbZ7/Q/fQZNnFrDUX6MXcYkuoNLUmKRagG5uq0UyIEtWgfyLtGJQlZ91KXJkvZsFQu+AO5dFiDceJA+IW11sCN5e/9gKWuHxzxwKepvA8S0lyPwQWYqk1V/O/bV5s5uD5zrI6Wndd8Yq7ejYsWd6ZeHbjrcTbbr35lKsTcpoLxtBjD+H/1X5+pYAPlW7ymLWpPxEAug8tnpzy5HVMtwNZ3br8S5afC9BgR7abGcfa3PjyYvM1tk6+JfCPLa9gIJShu1+eXTq0GUQnxu/0bL/ihnwadHlFZyLVzmRjBkPrsuQsM6KTvXS5Gw+BGo+zy/p7iFUFHws1r6zZNONe0ZxTudpDgGN7IoXmvyj7OOJ7VyGROggB0Ptu2iiNz81uTT1M9z+QCR2pa9E+a6fTWTZIXP86acb8HuKDb8Rd9wkU4G609aZc3QHX0ANKIFSWqhz9WDh0XZgT8daMuda+TmtI4NkTS7j9yQLqvbYQ1W2RpCKVBLgXCgiylBoHfRWFZ/dlOdkojBWaFnWa8ytU69IHFgVAd4V4RVPgjNyWgwovtQtiAvpT3o=';

if (verifyDigitalSignature($signature, $publicKey, $requestBody)) {
    console.log("Signature is valid!")
} else {
    console.log("Signature is not valid.")
}
<?php
// Signature is base64 encoded and found in the 'signature' header on the request
// Public Key returned from Extend API as base64 encoded string
// Request body. Stringified JSON body sent in the webhook request
function verifyDigitalSignature($signature, $publicKey, $requestBody)
{
    // Load the public key
    $publicKeyResource = openssl_pkey_get_public(base64_decode($publicKey));

    if ($publicKeyResource === false) {
        return false; // Failed to load the public key
    }

    // Verify the signature
    $result = openssl_verify($requestBody, base64_decode($signature), $publicKeyResource, OPENSSL_ALGO_SHA256);


    return ($result === 1); // 1 means the signature is valid
}

// Example usage
$publicKey = 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUF0dkZQY08rbFNVY1c5bi9kdjQ1dwpmWTB5RjQ3Q1haTElDcVM1a1dJeXBmcFAyTlg0V1JESzhjMGJYeDZnOVA0bi9VakpxeURzYStvY01pbDJkV1JECm4yb0dDenJaTHZrNmJ3ZXJRZkNpajBRdnk5MllaQVdKOHIyUXJRTjY5TFp6cnpDcXBNYmxlY2xiNGR1NUw0NnQKSWRXcE91V3g5SldPRC9GL0hST3lkMjYrU0lVdnJzTG5rN3BqU3NSeDFCcDltdytxaklCMnRFRkNJTnJEM0lEYwpGaWNQS01wV0ltaE5BK0J1a3EzWnlTenEyVnZxQXFtaGlmNUVzTHc0WFdYT3VjTTdZV0xuNU1mc2NSaXBwd2t5Cjk0ZW1WRDRIYzNMYUlZZGp4Y1NNZDlHeXI0dmdFUVUrc2dqL2hyQmZqQ2FiTEVzZkVMSWJyQzRhUGFOTjFWVGEKcjkxRXJ5Y0V0bUg1Zk5BaEk3a2ExWVVGdDUrQWd2WERjUHM0dm5IdVRYODZURy8wSU1oU3hyK2p2ZGFyWUpiVApkYkxVMitWaVJTakljM0ZTZzRxanZ4bXlmSk5Ya3dJV0h5NU1oM2tFSzNHQTU3M0dvZnlDVGpvMjBJd2pOd2h5CnMwUGRNbkM5WVhKUUFUUEU0QnZBRGFhQTRVaUtEZU1mcE9YQTRZNmRnQTlIRFJWb0EwUmdOQXljZkhoMGVJeWoKbk9aamFVN25hcEF4UWpyN3hxVHcvOGQ4L01wQ2RBYUFiNzBpTDVwYmJBdFhwdWhCMjdmdktOZ3ZRR0QzK1g2aQpkRWJNWXVKbVpIenFETWZFbUpST2Q0U2pRbDBPUjVMYXk1S3BaeXZqVnNza2gwR0ViVS9IUjg3VVlQOEZKbithCnZEaEc2alUrSHRTREphaEFDWGVhUytzQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==';

$requestBody = '{"serviceOrderId":"73752710-8cdf-4fe3-8327-6936fa3badd6","claimId":"7b67180d-0ae6-4d81-a0ca-d7eeda41870e","contractId":"770e5f9d-fb2d-4c53-9137-cbb647d037f5","servicerId":"26db19a3-d9db-4ad4-9575-b7ca2f6e990a","customerName":"Paul Name","customerEmail":"[email protected]","contractPurchaseDate":1655668093818,"customerShippingAddress":{"city":"San Francisco","address1":"533 Mission Street","provinceCode":"CA","countryCode":"USA","postalCode":"94105"},"customerPhoneNumber":"555-535-5555","productDetails":[{"productReferenceId":"PRODUCT-REPAIR-385UmuLNaUqVmpohrmnvMqrncttQCz","productListPrice":25199,"productPurchasePrice":25199}],"failureType":"webhook parse","failureDescription":"webhook","incident":{"failureType":"electricalFailure","description":"BROKE PLZ HALP","occurredAt":1695152893819,"FailureType":"webhook parse","FailureDescription":"webhook","productCondition":"nonfunctional"},"sendDate":1695152952396,"url":"https://webhook.site/70a09585-f934-4b01-855b-0869e5e19752","transactionId":"63815176-f685-44ca-8180-fb13e39d5d04","type":"assign"}';
$signature = 'JJbRyjmmylP4GJtNCT7wANYVMkmUYENuX13sXqMjbAUcfidBBix/hzCjnoycg6lCT1Ktny2OnmixEHQAwNFOuReTlid+AFvCQnQ0nA+aUjvD3JSYCLLE2SOuvbZ7/Q/fQZNnFrDUX6MXcYkuoNLUmKRagG5uq0UyIEtWgfyLtGJQlZ91KXJkvZsFQu+AO5dFiDceJA+IW11sCN5e/9gKWuHxzxwKepvA8S0lyPwQWYqk1V/O/bV5s5uD5zrI6Wndd8Yq7ejYsWd6ZeHbjrcTbbr35lKsTcpoLxtBjD+H/1X5+pYAPlW7ymLWpPxEAug8tnpzy5HVMtwNZ3br8S5afC9BgR7abGcfa3PjyYvM1tk6+JfCPLa9gIJShu1+eXTq0GUQnxu/0bL/ihnwadHlFZyLVzmRjBkPrsuQsM6KTvXS5Gw+BGo+zy/p7iFUFHws1r6zZNONe0ZxTudpDgGN7IoXmvyj7OOJ7VyGROggB0Ptu2iiNz81uTT1M9z+QCR2pa9E+a6fTWTZIXP86acb8HuKDb8Rd9wkU4G609aZc3QHX0ANKIFSWqhz9WDh0XZgT8daMuda+TmtI4NkTS7j9yQLqvbYQ1W2RpCKVBLgXCgiylBoHfRWFZ/dlOdkojBWaFnWa8ytU69IHFgVAd4V4RVPgjNyWgwovtQtiAvpT3o=';

if (verifyDigitalSignature($signature, $publicKey, $requestBody)) {
    echo "Signature is valid!";
} else {
    echo "Signature is not valid.";
}
?>

If the signature verification succeeds; process the webhook. If verification fails; reject the webhook.

Webhook Request Body

The webhook request body is the same shape for all of the following supported claims events:

approved: 'claim_approved', denied: 'claim_denied', review: 'claim_in_review',

Events can be subscribed to on an individual basis.

export interface ClaimWebhookData {
  // Contract and order identifiers
  contractId?: string
  orderId?: string
  claimId: string

  // Claim details
  claimType: ClaimType
  claimStatus: ClaimStatus
  transactionId: string
  remainingLimitOfLiability?: number
  validationReason?: ClaimValidationReason
  coverageTerm?: {
    startDate: number
    endDate: number
  }
  // Customer and product information
  customer: ClaimCustomerInformation
  products: ClaimProduct[]
  incident: ClaimFailureInformation
  reportedAt: number
  // Webhook metadata
  sendDate: number
  type: string
  url: string
  kid: string

  // Optional fields
  denialReason?: ClaimDenialReason
}

Approved Example

{
  "contractId": "51d1699c-c8f4-4e50-893b-16af8adc994a",
  "orderId": "e18c4150-2bcb-4d80-94af-816f9c59e0e1",
  "claimId": "fc47a847-27c8-48c3-a564-68300f5f625b",
  "claimType": "extended_warranty",
  "claimStatus": "approved",
  "transactionId": "6c7278d7-37a5-4253-ba8d-3d266bc68b2a",
  "remainingLimitOfLiability": 2000,
  "validationReason": "shipping_delivery_waiting_period",
  "coverageTerm": {
    "startDate": 1593533340000,
		"endDate": 1593993600000,
  },
  "customer": {
    "name": "John Doe",
    "phone": "111-111-1111",
    "email": "[email protected]",
    "shippingAddress": {
			"address1": "1 Main St",
			"address2": "Ste 1",
    	"city": "San Francisco",
    	"provinceCode": "CA",
    	"countryCode": "US",
      "postalCode": "11111",
    }
  },
  "products": [{
    "referenceId": "referenceId",
    "lineItemId": "05f40503-33c4-42d8-9441-e060f34b6002",
    "limitOfLiability": {
      "amount": 2000,
      "currencyCode": "USD",
    },
    "title": "black t-shirt",
    "components": [{
      "referenceId": "c0cbe99f-c548-4395-8176-7cb7ab91ab8b",
      "productReferenceId": "referenceId",
      "value": {
			  "amount": 2000,
      	"currencyCode": "USD",
      },
			"title": "black t-shirt",
    }]
  }],
  "incident": {
    "FailureType": "shipment_lost",
    "FailureDescription": "The package has been rerouted to the correct destination.",
		"Shipment": "1Z57E4700306164050",
    "IncidentDate": 1756699200000,
    "ContractId": "762b3bcd-4689-4a02-a609-d1678dba96d5",
    "LineItemIds": ["3455277d-e8bb-47b2-a4cf-825588884de8"],
    "AdjudicationCategory": "shipping_protection",
  },
  "reportedAt": 1740766088101,
  "sendDate": 1740766088101,
  "type": "claim_approved",
  "url": "https://servicer-webhook-url/post-webhook",
  "kid": "b35edb9f-4be9-4cb4-9425-6f3d04ac9347",
}

Denied Example

{
  "contractId": "51d1699c-c8f4-4e50-893b-16af8adc994a",
  "orderId": "e18c4150-2bcb-4d80-94af-816f9c59e0e1",
  "claimId": "fc47a847-27c8-48c3-a564-68300f5f625b",
  "claimType": "extended_warranty",
  "claimStatus": "denied",
  "transactionId": "6c7278d7-37a5-4253-ba8d-3d266bc68b2a",
  "remainingLimitOfLiability": 2000,
  "validationReason": "mfr_warranty_active",
  "coverageTerm": {
    "startDate": 1593533340000,
		"endDate": 1593993600000,
  },
  "customer": {
    "name": "John Doe",
    "phone": "111-111-1111",
    "email": "[email protected]",
    "shippingAddress": {
			"address1": "1 Main St",
			"address2": "Ste 1",
    	"city": "San Francisco",
    	"provinceCode": "CA",
    	"countryCode": "US",
      "postalCode": "11111",
    }
  },
  "products": [{
    "referenceId": "referenceId",
    "lineItemId": "05f40503-33c4-42d8-9441-e060f34b6002",
    "limitOfLiability": {
      "amount": 2000,
      "currencyCode": "USD",
    },
    "title": "black t-shirt",
    "components": [{
      "referenceId": "c0cbe99f-c548-4395-8176-7cb7ab91ab8b",
      "productReferenceId": "referenceId",
      "value": {
			  "amount": 2000,
      	"currencyCode": "USD",
      },
			"title": "black t-shirt",
    }]
  }],
  "incident": {
    "FailureType": "failure_electrical",
    "FailureDescription": "a",
    "IncidentDate": 1756699200000,
    "ContractId": "762b3bcd-4689-4a02-a609-d1678dba96d5",
    "LineItemIds": ["3455277d-e8bb-47b2-a4cf-825588884de8"],
    "AdjudicationCategory": "consumer_electronics",
    "FailureCause": "weather"
  },
  "reportedAt": 1740766088101,
  "sendDate": 1740766088101,
  "type": "claim_denied",
  "url": "https://servicer-webhook-url/post-webhook",
  "kid": "b35edb9f-4be9-4cb4-9425-6f3d04ac9347",
  "denialReason": "under_manufacturer_warranty",
}

Webhooks should be responded to with a status code 200. All requests that do not receive a 200 will be retried every hour for 48 hours.

Language