What is a webhook?

Carbon employs webhooks to promptly transmit real-time notifications regarding your Carbon actions. These webhooks consistently utilize HTTPS for secure data transmission and deliver JSON payloads, seamlessly integrable into your application. Leverage webhook feeds to streamline various tasks, including:

  • Retrieval of documents, chunks and embeddings.
  • Generation of alerts within messaging or incident management tools, triggered by specific event types.
  • Comprehensive storage of all transmission events in your database for tailored reporting and extended data retention.

Steps to receive webhooks

Currently, there is no way to choose which events to receive webhooks for - it’s on our roadmap to allow for more fine-grained filtering.

The steps in setting up webhooks for your service are:

  1. Add a URL to which webhoooks should be sent. This can be done using the /add_webhook endpoint.
  2. Save the signing_key in the response somewhere safe - this can’t be retrieved again.
You can create a tunnel to your localhost server using a tool like ngrok. For example: https://5f9f-98-14-198-85.ngrok-free.app/api/webhook

At this point, all events will be sent to the URL specified in Step 1. An event - sent via an HTTP POST request - contains two important elements, a Carbon-Signature header and a body with a single key-value pair. You can validate the authenticity and integrity of the webhook by calculating its signature.

To do this, you should:

  1. Extract the timestamp and signature.
    1. Extract the timestamp and signature from the Carbon-Signature header. It will be of the form Carbon-Signature:t=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd.
    2. For those using JavaScript and decoding the request json via JSON.stringify, we suggest using the Carbon-Signature-Compact header instead. It will have the form Carbon-Signature:t=1492774577,v2=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd.
  2. Create a string of the form {timestamp}.{request_body}, where request_body is the entire request body. Note that all values in the webhook request body are coerced to strings - this is intentional.
    1. If using Carbon-Signature, you can use request_body as is, or you can decode it as json. When decoding, ensure that the resulting json is formatted exactly as it is in request_body. In other words, the json should look like:
{"x": 5, "y": 6}
  1. If using Carbon-Signature-V2, when decoding the request body, ensure that the resulting json is in compact form, where there are no spaces between key-value pairs or between keys and values. For example,
{"x":5,"y":6}

Given a request body, x, you can do this in Python via json.dumps(x, separators=[",", ":"]) or in JavaScript via JSON.stringify(x).

  1. Compute an HMAC of the above string with the SHA256 hash function. Use signing_key obtained from the /add_webhook endpoint as the key.
Please decode the signing key as a hex string.
  1. Compare the computed signature with the signature in the header (the value that v1 - or v2 - is equal to). If they’re identical, you can be assured that the webhook is both genuine and hasn’t been tampered with.

Once you receive and handle the webhook, you should respond to the POST request with a 200 status - otherwise the webhook will be retried (up to three times).

An organization is allowed up to 3 webhook URLs. To delete an existing URL, you can use the /delete_webhook endpoint. To view all existing webhooks, use the /webhooks endpoint.

All webhook payloads have the form

{
    "payload": str
}

The value of payload (which is a stringified json object) will always have the form

{
    "webhook_type": WebhookType,
    "obj": {
        "object_type": WebhookObjectType,
        "object_id": str,
        "additional_information": dict[str, str] | str
    },
    "timestamp": str
}

Please note that the WebhookType refers to specific events outlined in the Event Types documentation. Presently, the WebhookObjectType is restricted to FILE.

The field additional_information consistently contains a dictionary of string-string key-value pairs. If empty, it defaults to the string value “null”.

The timestamp field is an integer POSIX timestamp presented as a string. To utilize object_id in subsequent API requests, it’s advisable to convert it into an integer. This object_id corresponds to the file_id of the file in question.

FAQ