curl --request POST \
--url https://api.tilta.io/v1/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({destination_url: '<string>', type: 'FACILITY.CREATION.ACCEPTED'})
};
fetch('https://api.tilta.io/v1/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.tilta.io/v1/webhooks"
payload = {
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tilta.io/v1/webhooks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'destination_url' => '<string>',
'type' => 'FACILITY.CREATION.ACCEPTED'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}{
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED",
"signature_key": "<string>",
"created_at": 1582896122,
"updated_at": 1582896122
}{
"code": "BAD_REQUEST",
"error": "Request validation failed. 1 issue found.",
"issues": [
{
"code": "INVALID_TYPE",
"path": "body.registered_at",
"message": "Invalid type"
}
]
}{
"error": "Unauthorized",
"code": "UNAUTHORIZED"
}{
"error": "Webhook with the same type already exists",
"code": "CONFLICT"
}Create a subscription
Subscribe to a Tilta webhook event type and receive real-time HTTP POST notifications at your endpoint whenever the specified event fires.
curl --request POST \
--url https://api.tilta.io/v1/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({destination_url: '<string>', type: 'FACILITY.CREATION.ACCEPTED'})
};
fetch('https://api.tilta.io/v1/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.tilta.io/v1/webhooks"
payload = {
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tilta.io/v1/webhooks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'destination_url' => '<string>',
'type' => 'FACILITY.CREATION.ACCEPTED'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}{
"destination_url": "<string>",
"type": "FACILITY.CREATION.ACCEPTED",
"signature_key": "<string>",
"created_at": 1582896122,
"updated_at": 1582896122
}{
"code": "BAD_REQUEST",
"error": "Request validation failed. 1 issue found.",
"issues": [
{
"code": "INVALID_TYPE",
"path": "body.registered_at",
"message": "Invalid type"
}
]
}{
"error": "Unauthorized",
"code": "UNAUTHORIZED"
}{
"error": "Webhook with the same type already exists",
"code": "CONFLICT"
}FACILITY – and a destination_url. Tilta delivers an HTTP POST request to that URL whenever a matching event occurs. The response includes a signature_key that you must store securely: it is shown only once and cannot be retrieved again.
signature_key is only visible in this creation response. Tilta does not store or re-expose it. If you lose it, rotate
the key to get a new one.Verifying webhook signatures
Every webhook request Tilta sends includes anX-Tilta-Signature header. Compute an HMAC-SHA256 digest of the raw request body using your signature_key and compare it to the header value to confirm the request is genuine.
import hmac
import hashlib
def verify_signature(payload_bytes: bytes, header: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
payload_bytes,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, header)
FACILITY, ORDER) during development so you can inspect all event shapes in one place.
Switch to specific leaf-event subscriptions in production to reduce noise and tighten access control.Authorizations
Your Tilta API key, sent as Bearer <key>.
Body
Where the webhook should be sent to. This must be an endpoint that handles POST requests.
The webhook's type. Supports the hierarchical dot-notation taxonomy; subscribing to a parent (e.g. FACILITY) implicitly subscribes to every descendant event (e.g. FACILITY.CREATION.ACCEPTED). Other valid values include ORDER.CONFIRMED and INVOICE.DUE.
BUYER, BUYER.CREATED, BUYER.UPDATED, FACILITY, FACILITY.CREATION, FACILITY.CREATION.ACCEPTED, FACILITY.CREATION.IN_REVIEW, FACILITY.CREATION.REJECTED, FACILITY.EXPIRED, FACILITY.FROZEN, FACILITY.INCREASE, FACILITY.INCREASE.ACCEPTED, FACILITY.INCREASE.IN_REVIEW, FACILITY.INCREASE.REJECTED, FACILITY.RENEWAL, FACILITY.RENEWAL.ACCEPTED, FACILITY.RENEWAL.IN_REVIEW, FACILITY.RENEWAL.REJECTED, FACILITY.UNFROZEN, INVOICE, INVOICE.CLOSED, INVOICE.CREATED, INVOICE.DUE, INVOICE.FILE, INVOICE.FILE.CREATED, INVOICE.FILE.DELETED, INVOICE.FILE.REPLACED, INVOICE.FINANCING, INVOICE.FINANCING.PAID_OUT, ORDER, ORDER.CANCELLED, ORDER.CLOSED, ORDER.CONFIRMED, ORDER.DISBURSED, ORDER.EXPIRED "FACILITY.CREATION.ACCEPTED"
Response
Where the webhook should be sent to. This must be an endpoint that handles POST requests.
The webhook's type. Supports the hierarchical dot-notation taxonomy; subscribing to a parent (e.g. FACILITY) implicitly subscribes to every descendant event (e.g. FACILITY.CREATION.ACCEPTED). Other valid values include ORDER.CONFIRMED and INVOICE.DUE.
BUYER, BUYER.CREATED, BUYER.UPDATED, FACILITY, FACILITY.CREATION, FACILITY.CREATION.ACCEPTED, FACILITY.CREATION.IN_REVIEW, FACILITY.CREATION.REJECTED, FACILITY.EXPIRED, FACILITY.FROZEN, FACILITY.INCREASE, FACILITY.INCREASE.ACCEPTED, FACILITY.INCREASE.IN_REVIEW, FACILITY.INCREASE.REJECTED, FACILITY.RENEWAL, FACILITY.RENEWAL.ACCEPTED, FACILITY.RENEWAL.IN_REVIEW, FACILITY.RENEWAL.REJECTED, FACILITY.UNFROZEN, INVOICE, INVOICE.CLOSED, INVOICE.CREATED, INVOICE.DUE, INVOICE.FILE, INVOICE.FILE.CREATED, INVOICE.FILE.DELETED, INVOICE.FILE.REPLACED, INVOICE.FINANCING, INVOICE.FINANCING.PAID_OUT, ORDER, ORDER.CANCELLED, ORDER.CLOSED, ORDER.CONFIRMED, ORDER.DISBURSED, ORDER.EXPIRED "FACILITY.CREATION.ACCEPTED"
Timestamp indicating when the webhook was created (unix time in seconds).
1582896122
Timestamp indicating the last time the webhook was updated (unix time in seconds).
1582896122