Validate Feed Webhook Destination
curl --request POST \
--url https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"error": "<string>"
}{
"error": "<string>"
}Webhooks
Validate Destination
Validate and test the functionality of your receiving endpoing by calling this endoint. Upon receiving this POST, we will make two requests to the destination URL:
- one without a signature
- one with a valid “Daylight-Signature” header.
Each request will contain an example feed item, allowing you to test parsing and validation. To receive a successful response from this request, your receiving endpoint must return a non-2xx response to the invalid request and a 2xx response to the valid one.
POST
/
v1
/
webhooks
/
feed
/
{uid}
/
validate
Validate Feed Webhook Destination
curl --request POST \
--url https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.clicker.xyz/v1/webhooks/feed/{uid}/validate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"error": "<string>"
}{
"error": "<string>"
}When a webhook alert pings your server, we provide a signature to verify that the alert is coming from us. This signature should match a hash of the incoming request’s body.
To perform this verification, you need:
- The secret generated when first creating the webhook
- The signature in the header daylight-signature
- The string of the body included in the request
Example verification function
import crypto from "crypto";
export function verifyDaylightWebhookSignature({
headerSignature,
body,
secret,
}: {
headerSignature: string | null | undefined;
body: string;
secret: string;
}) {
//Step 1: Extract the timestamp and signatures from the header
// (the signature var in this case)
const sigSplit = (headerSignature || "").split(",") || [];
let timestamp: string | undefined = undefined;
let signature: string | undefined = undefined;
for (const element of sigSplit) {
const [key, value] = element.split("=");
if (key === "t") {
timestamp = value;
} else if (key === "v1") {
signature = value;
}
}
if (!signature || !timestamp) {
throw new Error(`Missing timestamp or signature in ${signature}`);
}
// Step 2: Prepare the signed_payload string
const toSign = `${timestamp}.${body}`;
//Step 3: Determine the expected signature
const hash = crypto
.createHmac("sha256", secret)
.update(toSign)
// use base64url instead of base64 to escape equal signs
// a header ending with an = is invalid!
.digest("base64url");
if (hash !== signature) {
throw new Error(`Incorrect signature value in ${signature}`);
}
return true;
}