curl --request GET \
--url https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keysimport requests
url = "https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys', 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://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"keys": [
{
"algorithm": "ed25519_v1",
"kid": "whk_1",
"public_key": "whpk_tuaUMN99+3lmXIpT0k7KusnxtBRgT5EMGAbyjTWLkJY=",
"valid_from": "2026-09-27T13:11:15.000Z"
}
],
"signature_scheme": "v1a"
}{
"error": {
"code": "invalid_request",
"details": {
"fields": [
{
"field": "target_url",
"problem": "Field required"
}
]
},
"message": "The request is invalid."
}
}{
"error": {
"code": "rate_limited",
"details": {
"retry_after_seconds": 42
},
"message": "Rate limit exceeded. Retry after the interval in the Retry-After header."
}
}{
"error": {
"code": "internal_error",
"details": {},
"message": "An internal error occurred. Retry with exponential backoff."
}
}Get the public key set
Returns the public keys that verify the workspace’s event signatures. Needs no authentication. An unknown workspace, or one with no keys yet, gets an empty keys list.
Keys come newest first, a page at a time; follow next_cursor until it’s null. A workspace holds one key, or two during a rotation, so the default page is usually the whole set.
The signature header carries no key ID, so try every key, and fetch the set again once when none verifies. During a key rotation, events carry one signature per key. Responses carry an ETag; send it back as If-None-Match to get 304 Not Modified when nothing changed. A non-empty set may be cached for 5 minutes. Rate limit: 600 requests a minute per client IP.
curl --request GET \
--url https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keysimport requests
url = "https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys', 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://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/v1/outbound-webhooks/workspaces/{workspace_id}/keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"keys": [
{
"algorithm": "ed25519_v1",
"kid": "whk_1",
"public_key": "whpk_tuaUMN99+3lmXIpT0k7KusnxtBRgT5EMGAbyjTWLkJY=",
"valid_from": "2026-09-27T13:11:15.000Z"
}
],
"signature_scheme": "v1a"
}{
"error": {
"code": "invalid_request",
"details": {
"fields": [
{
"field": "target_url",
"problem": "Field required"
}
]
},
"message": "The request is invalid."
}
}{
"error": {
"code": "rate_limited",
"details": {
"retry_after_seconds": 42
},
"message": "Rate limit exceeded. Retry after the interval in the Retry-After header."
}
}{
"error": {
"code": "internal_error",
"details": {},
"message": "An internal error occurred. Retry with exponential backoff."
}
}Headers
Path Parameters
The workspace's ID.
"67f3954555578059d9273f7e"
Query Parameters
How many keys to return.
1 <= x <= 5010
The next_cursor from the previous page. Omit it for the first page.
"gAAAAABn7vJx..."
Response
Successful Response
The keys that currently sign the workspace's events.
This page of keys, newest first. Empty when the workspace has none.
Show child attributes
Show child attributes
The scheme tag in the webhook-signature header. Always v1a.
Opaque continuation token. Null on the last page. Pass it back as cursor; a receiver needs every page to verify during a rotation.
Was this page helpful?