Skip to main content

Webhooks

Webhooks are automated messages sent from our system when something happens. They have a message or payload and are sent to a unique URL, essentially a simple way for Karla to communicate with your systems automatically. This allows you to receive real-time data about specific events without needing to poll our server continuously for updates.

See API Webhooks Reference for more information in how to set them up programmatically.

How to setup

See the Webhook Entity for more details on the API operations.

You can enable the webhooks using the Create Webhook endpoint.

POST /v1/shops/{slug}/webhooks
{
"enabled_events": [
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered"
],
"secret": "41013bd9-9072-42cd-9902-66da38361be9",
"description": "Shipment Deliveries",
"status": "active",
"url": "https://example.com/my-webhook-endpoint"
}

If no enabled_events is provided, the webhook will listen to ALL events (["*"]). See Event Filtering for more information about how to listen to specific events or event groups.

You can check which webhooks are defined in your shop using the Search Webhook endpoint.

Webhooks can be updated once they are live, using the Update Webhook endpoint.

PATCH /v1/shops/{slug}/webhooks/{uuid}
{
"description": "My new description",
"url": "https://example.com/my-new-webhook-endpoint"
}

You can delete webhooks with the Delete Webhook endpoint.

Securing your endpoint

You should secure your integration by making sure your handler verifies that all webhook requests are generated by Karla.

We include a Karla-Signature header in each signed event that contains a timestamp and a signature that you should verify. The timestamp has a t= prefix, and the signature has a v1= prefix.

Karla-Signature:
t=1710864000,
v1=7f3a8b2c1d9e4f6a5b8c7d0e3f2a1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
note

We provide newlines for clarity, but a real Karla-Signature header is on a single line.

Karla generates signatures using a hash-based message authentication code (HMAC) with SHA-256.

Verify the signature

  1. Extract the timestamp and signatures from the header.
  2. Concatenate the timestamp as a string with . and the actual JSON payload.
  3. Compute an HMAC with the SHA256 hash function. Use the provided signing secret as the key.
  4. Compare the signature in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

Webhook Verification Sample Code

Node.js/TypeScript

Webhook Verification (Node.js)
import crypto from "crypto";

function verifyKarlaSignature(
payload: string,
signature: string,
secret: string,
): boolean {
const elements = signature.split(",");
const timestamp = elements.find((el) => el.startsWith("t="))?.split("=")[1];
const providedSignature = elements
.find((el) => el.startsWith("v1="))
?.split("=")[1];

if (!timestamp || !providedSignature) {
return false;
}

const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(signedPayload)
.digest("hex");

return crypto.timingSafeEqual(
Buffer.from(providedSignature, "hex"),
Buffer.from(expectedSignature, "hex"),
);
}

// Usage
const isValid = verifyKarlaSignature(
JSON.stringify(webhookPayload),
request.headers["karla-signature"],
"your-webhook-secret",
);

Python

Webhook Verification (Python)
import hmac
import hashlib
import time

def verify_karla_signature(payload: str, signature: str, secret: str) -> bool:
elements = signature.split(',')
timestamp = next((el.split('=')[1] for el in elements if el.startswith('t=')), None)
provided_signature = next((el.split('=')[1] for el in elements if el.startswith('v1=')), None)

if not timestamp or not provided_signature:
return False

signed_payload = f"{timestamp}.{payload}"
expected_signature = hmac.new(
secret.encode('utf-8'),
signed_payload.encode('utf-8'),
hashlib.sha256
).hexdigest()

return hmac.compare_digest(provided_signature, expected_signature)

# Usage
is_valid = verify_karla_signature(
json.dumps(webhook_payload),
request.headers.get('karla-signature'),
'your-webhook-secret'
)

Retry strategy

Karla sends data to your handler via POST. In case of an unsuccessful event (non 2xx response), or if your endpoint takes longer than 10s to respond, Karla attempts to deliver your webhooks for up to 15 times with an exponential back off. The event will be lost if all attempts are exhausted.

Specification

Host: api.gokarla.io
Content-Length: 12345
Accept: application/json
Karla-Signature: t=1710864000,v1=7f3a8b2c1d9e4f6a5b8c7d0e3f2a1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
Content-Type: application/json

Body

Body follows the format described in event payload.

IP Whitelisting

If your service has a Firewall restricting public IPs, please add 34.77.48.225 to the allow list.