curl --request POST \
--url https://{command_center_host}/api/v1/signals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sid": "scheduler__admin__search__RMD5_at_1791534708_42",
"search_name": "Disk full on state volume",
"app": "search",
"result": {
"problem": "<string>",
"message": "<string>",
"description": "<string>",
"host": "<string>",
"ip": "<string>",
"dest_ip": "<string>",
"src_ip": "<string>",
"sourceIPAddress": "<string>",
"severity": "<string>",
"detected_at": "1791534708.512"
}
}
'import requests
url = "https://{command_center_host}/api/v1/signals"
payload = {
"sid": "scheduler__admin__search__RMD5_at_1791534708_42",
"search_name": "Disk full on state volume",
"app": "search",
"result": {
"problem": "<string>",
"message": "<string>",
"description": "<string>",
"host": "<string>",
"ip": "<string>",
"dest_ip": "<string>",
"src_ip": "<string>",
"sourceIPAddress": "<string>",
"severity": "<string>",
"detected_at": "1791534708.512"
}
}
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({
sid: 'scheduler__admin__search__RMD5_at_1791534708_42',
search_name: 'Disk full on state volume',
app: 'search',
result: {
problem: '<string>',
message: '<string>',
description: '<string>',
host: '<string>',
ip: '<string>',
dest_ip: '<string>',
src_ip: '<string>',
sourceIPAddress: '<string>',
severity: '<string>',
detected_at: '1791534708.512'
}
})
};
fetch('https://{command_center_host}/api/v1/signals', 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://{command_center_host}/api/v1/signals",
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([
'sid' => 'scheduler__admin__search__RMD5_at_1791534708_42',
'search_name' => 'Disk full on state volume',
'app' => 'search',
'result' => [
'problem' => '<string>',
'message' => '<string>',
'description' => '<string>',
'host' => '<string>',
'ip' => '<string>',
'dest_ip' => '<string>',
'src_ip' => '<string>',
'sourceIPAddress' => '<string>',
'severity' => '<string>',
'detected_at' => '1791534708.512'
]
]),
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://{command_center_host}/api/v1/signals"
payload := strings.NewReader("{\n \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\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://{command_center_host}/api/v1/signals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{command_center_host}/api/v1/signals")
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 \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\n}"
response = http.request(request)
puts response.read_body{
"signal_id": "sig_e4499e94-91ad-4954-9a01-15bd63abc061",
"fingerprint": "2fb7c6ca597df4ed",
"occurrence_count": 1
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}Receive a Splunk alert
Experimental: this endpoint and its body may change in later releases. The URL for a Splunk alert action. It takes the signal key of one organization, created with 2501 infra webhook create --source-type splunk, and records the alert as a signal of that organization, whatever the body says. An API key or a session is refused with 401. The key is checked before the body, so a request without a valid key gets 401 and nothing else. Alerts from the same search with the same text and machine are counted into one signal; occurrence_count is its count so far. A redelivery of a sid already recorded answers 200 with already_counted and is not counted again, so Splunk can resend safely. Observability turned off for the installation answers 403. Errors from this route carry code ENGINE_ERROR.
curl --request POST \
--url https://{command_center_host}/api/v1/signals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sid": "scheduler__admin__search__RMD5_at_1791534708_42",
"search_name": "Disk full on state volume",
"app": "search",
"result": {
"problem": "<string>",
"message": "<string>",
"description": "<string>",
"host": "<string>",
"ip": "<string>",
"dest_ip": "<string>",
"src_ip": "<string>",
"sourceIPAddress": "<string>",
"severity": "<string>",
"detected_at": "1791534708.512"
}
}
'import requests
url = "https://{command_center_host}/api/v1/signals"
payload = {
"sid": "scheduler__admin__search__RMD5_at_1791534708_42",
"search_name": "Disk full on state volume",
"app": "search",
"result": {
"problem": "<string>",
"message": "<string>",
"description": "<string>",
"host": "<string>",
"ip": "<string>",
"dest_ip": "<string>",
"src_ip": "<string>",
"sourceIPAddress": "<string>",
"severity": "<string>",
"detected_at": "1791534708.512"
}
}
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({
sid: 'scheduler__admin__search__RMD5_at_1791534708_42',
search_name: 'Disk full on state volume',
app: 'search',
result: {
problem: '<string>',
message: '<string>',
description: '<string>',
host: '<string>',
ip: '<string>',
dest_ip: '<string>',
src_ip: '<string>',
sourceIPAddress: '<string>',
severity: '<string>',
detected_at: '1791534708.512'
}
})
};
fetch('https://{command_center_host}/api/v1/signals', 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://{command_center_host}/api/v1/signals",
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([
'sid' => 'scheduler__admin__search__RMD5_at_1791534708_42',
'search_name' => 'Disk full on state volume',
'app' => 'search',
'result' => [
'problem' => '<string>',
'message' => '<string>',
'description' => '<string>',
'host' => '<string>',
'ip' => '<string>',
'dest_ip' => '<string>',
'src_ip' => '<string>',
'sourceIPAddress' => '<string>',
'severity' => '<string>',
'detected_at' => '1791534708.512'
]
]),
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://{command_center_host}/api/v1/signals"
payload := strings.NewReader("{\n \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\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://{command_center_host}/api/v1/signals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{command_center_host}/api/v1/signals")
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 \"sid\": \"scheduler__admin__search__RMD5_at_1791534708_42\",\n \"search_name\": \"Disk full on state volume\",\n \"app\": \"search\",\n \"result\": {\n \"problem\": \"<string>\",\n \"message\": \"<string>\",\n \"description\": \"<string>\",\n \"host\": \"<string>\",\n \"ip\": \"<string>\",\n \"dest_ip\": \"<string>\",\n \"src_ip\": \"<string>\",\n \"sourceIPAddress\": \"<string>\",\n \"severity\": \"<string>\",\n \"detected_at\": \"1791534708.512\"\n }\n}"
response = http.request(request)
puts response.read_body{
"signal_id": "sig_e4499e94-91ad-4954-9a01-15bd63abc061",
"fingerprint": "2fb7c6ca597df4ed",
"occurrence_count": 1
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}{
"code": "VALIDATION_FAILED",
"message": "Validation failed",
"request_id": "req_3702b7e7-...",
"field": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
],
"details": {}
}Authorizations
A per-organization signal key, created with 2501 infra webhook create --source-type splunk and shown once, sent as Authorization: Bearer 2501_wh_.... It is accepted only by POST /api/v1/signals.
Body
The JSON body Splunk sends for an alert action.
The search job ID. It identifies the firing, so a redelivery is not counted twice. A multivalue sid uses its first value.
"scheduler__admin__search__RMD5_at_1791534708_42"
The saved search. It is the signal text when the result has none.
"Disk full on state volume"
The Splunk app the search runs in. It is kept with the signal.
"search"
The first result row of the search. The first of problem, message and description present is the signal text, and the first of host, ip, dest_ip, src_ip and sourceIPAddress names the machine. Every column is kept with the signal. A multivalue field uses its first value.
Show child attributes
Show child attributes
Response
The signal the alert was counted into

