curl --request POST \
--url https://app.base44.com/api/v1/outbound-webhooks/endpoints \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "Production receiver",
"selected_event_types": [
"app.created.v1",
"app.deleted.v1"
],
"target_url": "https://hooks.example.com/base44"
}
'import requests
url = "https://app.base44.com/api/v1/outbound-webhooks/endpoints"
payload = {
"description": "Production receiver",
"selected_event_types": ["app.created.v1", "app.deleted.v1"],
"target_url": "https://hooks.example.com/base44"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Production receiver',
selected_event_types: ['app.created.v1', 'app.deleted.v1'],
target_url: 'https://hooks.example.com/base44'
})
};
fetch('https://app.base44.com/api/v1/outbound-webhooks/endpoints', 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/endpoints",
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([
'description' => 'Production receiver',
'selected_event_types' => [
'app.created.v1',
'app.deleted.v1'
],
'target_url' => 'https://hooks.example.com/base44'
]),
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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/v1/outbound-webhooks/endpoints"
payload := strings.NewReader("{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.base44.com/api/v1/outbound-webhooks/endpoints")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/v1/outbound-webhooks/endpoints")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}"
response = http.request(request)
puts response.read_body{
"activated": true,
"detail": "",
"endpoint": {
"activated_at": "2026-10-04T19:25:39.423Z",
"consecutive_failed_deliveries": 0,
"created_date": "2026-10-04T19:25:34.260Z",
"description": "Provisioning",
"health": "healthy",
"id": "6ac2a82edfafd1b6c6a9c27d",
"last_success_at": "2026-10-05T13:23:36.743Z",
"selected_event_types": [
"app.created.v1",
"app.deleted.v1"
],
"state": "active",
"target_url": "https://hooks.example.com/base44"
},
"http_status": 200
}{
"error": {
"code": "invalid_request",
"message": "The request is invalid.",
"details": {
"fields": [
{
"field": "target_url",
"problem": "Field required"
}
]
}
}
}{
"error": {
"code": "unauthenticated",
"message": "Invalid workspace API key.",
"details": {}
}
}{
"error": {
"code": "permission_denied",
"message": "This workspace API key is not permitted to manage outbound webhooks. Needed: [outbound_webhooks:write]",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "Webhook endpoint not found.",
"details": {}
}
}{
"error": {
"code": "limit_exceeded",
"message": "A workspace may have at most 10 webhook endpoints.",
"details": {
"max_endpoints": 10
}
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after the interval in the Retry-After header.",
"details": {
"retry_after_seconds": 42
}
}
}{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Retry with exponential backoff.",
"details": {}
}
}Register an endpoint
Registers an endpoint and tests it in the same call. The test is a signed webhook.test.v1 event. The endpoint activates only if it answers with a 2xx status within 5 seconds and returns the event’s data.challenge in its response body. activated says whether it did; when it didn’t, failure_category, http_status and detail say why. The response is 201 either way, because the endpoint was created: retry a failed test with POST /endpoints/{endpoint_id}/test, not by registering again. Registering isn’t idempotent: if you lose the response, list the endpoints before retrying. A workspace can have up to 10 endpoints.
curl --request POST \
--url https://app.base44.com/api/v1/outbound-webhooks/endpoints \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "Production receiver",
"selected_event_types": [
"app.created.v1",
"app.deleted.v1"
],
"target_url": "https://hooks.example.com/base44"
}
'import requests
url = "https://app.base44.com/api/v1/outbound-webhooks/endpoints"
payload = {
"description": "Production receiver",
"selected_event_types": ["app.created.v1", "app.deleted.v1"],
"target_url": "https://hooks.example.com/base44"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Production receiver',
selected_event_types: ['app.created.v1', 'app.deleted.v1'],
target_url: 'https://hooks.example.com/base44'
})
};
fetch('https://app.base44.com/api/v1/outbound-webhooks/endpoints', 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/endpoints",
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([
'description' => 'Production receiver',
'selected_event_types' => [
'app.created.v1',
'app.deleted.v1'
],
'target_url' => 'https://hooks.example.com/base44'
]),
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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/v1/outbound-webhooks/endpoints"
payload := strings.NewReader("{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.base44.com/api/v1/outbound-webhooks/endpoints")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/v1/outbound-webhooks/endpoints")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Production receiver\",\n \"selected_event_types\": [\n \"app.created.v1\",\n \"app.deleted.v1\"\n ],\n \"target_url\": \"https://hooks.example.com/base44\"\n}"
response = http.request(request)
puts response.read_body{
"activated": true,
"detail": "",
"endpoint": {
"activated_at": "2026-10-04T19:25:39.423Z",
"consecutive_failed_deliveries": 0,
"created_date": "2026-10-04T19:25:34.260Z",
"description": "Provisioning",
"health": "healthy",
"id": "6ac2a82edfafd1b6c6a9c27d",
"last_success_at": "2026-10-05T13:23:36.743Z",
"selected_event_types": [
"app.created.v1",
"app.deleted.v1"
],
"state": "active",
"target_url": "https://hooks.example.com/base44"
},
"http_status": 200
}{
"error": {
"code": "invalid_request",
"message": "The request is invalid.",
"details": {
"fields": [
{
"field": "target_url",
"problem": "Field required"
}
]
}
}
}{
"error": {
"code": "unauthenticated",
"message": "Invalid workspace API key.",
"details": {}
}
}{
"error": {
"code": "permission_denied",
"message": "This workspace API key is not permitted to manage outbound webhooks. Needed: [outbound_webhooks:write]",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "Webhook endpoint not found.",
"details": {}
}
}{
"error": {
"code": "limit_exceeded",
"message": "A workspace may have at most 10 webhook endpoints.",
"details": {
"max_endpoints": 10
}
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after the interval in the Retry-After header.",
"details": {
"retry_after_seconds": 42
}
}
}{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Retry with exponential backoff.",
"details": {}
}
}Authorizations
A workspace API key with the outbound_webhooks:write scope, sent as Authorization: Bearer <key>.
Body
The HTTPS URL that receives events. It must resolve to public addresses, can't contain credentials, and must answer directly: redirects aren't followed.
2048The event types to send, such as app.created.v1. Each type is a separate version.
1 - 64 elementsA note for your own reference, up to 200 characters.
200Response
Successful Response
The endpoint and the result of its activation test.
Show child attributes
Show child attributes
{
"activated_at": "2026-10-04T19:25:39.423Z",
"consecutive_failed_deliveries": 0,
"created_date": "2026-10-04T19:25:34.260Z",
"description": "Provisioning",
"health": "healthy",
"id": "6ac2a82edfafd1b6c6a9c27d",
"last_success_at": "2026-10-05T13:23:36.743Z",
"selected_event_types": ["app.created.v1", "app.deleted.v1"],
"state": "active",
"target_url": "https://hooks.example.com/base44"
}
Whether the endpoint passed the test and is active.
The status your endpoint answered with. Null when it didn't answer.
Why the test failed: timeout, transport (no connection), server_error (5xx), client_error (4xx, or a 2xx without the challenge), redirect, ssrf_rejected (the URL resolved to a non-public address) or internal. Null on success.
A sentence explaining the result. Not a stable contract.
Was this page helpful?