set -eu
umask 077
# Path values must be URL-encoded; query string excludes the leading question mark.
url="${HD_BASE_URL:?Set API origin}/v1/partner/webhook-endpoints/${HD_PATH_ENDPOINT_ID:?Set the path fixture}/test/${HD_QUERY_STRING:+?${HD_QUERY_STRING}}"
printf 'Accept: application/json\n' > "${HD_REQUEST_HEADERS_FILE:?Private header file}"
printf 'Authorization: Bearer %s\n' "${HD_PARTNER_API_KEY:?Set partner API key}" >> "$HD_REQUEST_HEADERS_FILE"
curl --silent --show-error --max-time 30 --request POST \
--header "@$HD_REQUEST_HEADERS_FILE" \
--dump-header "${HD_HEADERS_FILE:?Private response header file}" \
--output "${HD_RESPONSE_FILE:?Private response file}" \
--write-out '%{http_code}\n%{content_type}\n' \
"$url"import os, json
from pathlib import Path
from urllib.parse import quote
import requests
os.umask(0o077)
url = os.environ["HD_BASE_URL"].rstrip("/") + '/v1/partner/webhook-endpoints/{endpoint_id}/test/'
url = url.replace('{endpoint_id}', quote(os.environ['HD_PATH_ENDPOINT_ID'], safe=""))
if os.environ.get("HD_QUERY_STRING"): url += "?" + os.environ["HD_QUERY_STRING"]
headers = {"Accept": 'application/json'}
headers["Authorization"] = "Bearer " + os.environ["HD_PARTNER_API_KEY"]
kwargs = {}
response = requests.request('POST', url, headers=headers, timeout=30, allow_redirects=False, **kwargs)
Path(os.environ["HD_RESPONSE_FILE"]).write_bytes(response.content)
Path(os.environ["HD_HEADERS_FILE"]).write_text(json.dumps(dict(response.headers)))
print(response.status_code)
print(response.headers.get("Content-Type", ""))
import { readFileSync, writeFileSync } from "node:fs";
const env = process.env;
let url = env.HD_BASE_URL.replace(/\/$/, "") + "/v1/partner/webhook-endpoints/{endpoint_id}/test/";
url = url.replace("{endpoint_id}", encodeURIComponent(env.HD_PATH_ENDPOINT_ID));
if (env.HD_QUERY_STRING) url += "?" + env.HD_QUERY_STRING;
const headers = { "Accept": "application/json" };
headers.Authorization = "Bearer " + env.HD_PARTNER_API_KEY;
const options = { method: "POST", headers, redirect: "manual", signal: AbortSignal.timeout(30000) };
const response = await fetch(url, options);
writeFileSync(env.HD_RESPONSE_FILE, Buffer.from(await response.arrayBuffer()), {mode: 0o600});
writeFileSync(env.HD_HEADERS_FILE, JSON.stringify(Object.fromEntries(response.headers)), {mode: 0o600});
console.log(response.status);
console.log(response.headers.get("content-type") ?? "");
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/",
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.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/"
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.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/")
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{
"id": "6e5d4c3b-2a19-4807-b6a5-948372615049",
"object": "webhook_delivery",
"endpoint_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"event_id": "2b3c4d5e-6f70-4182-93a4-b5c6d7e8f901",
"event_type": "endpoint.test",
"status": "pending",
"attempt_count": 0,
"next_attempt_at": "2026-11-03T12:40:00Z",
"last_attempt_at": null,
"delivered_at": null,
"response_status": null,
"response_excerpt": "",
"error": "",
"created_at": "2026-11-03T12:40:00Z"
}Send a test event
Queues an endpoint.test event to this endpoint only. The endpoint must be enabled. Requires the consultations:read, prescriptions:read and webhooks:manage scopes.
Access, effects and retries
Ownership: The API key’s own partner and mode (test or live); another partner’s or mode’s records answer 404.
Prerequisites: A partner API key with the webhooks:manage and consultations:read and prescriptions:read scopes.
Effects: Queues one endpoint.test delivery to this endpoint.
Retries: Each call queues another test delivery.
set -eu
umask 077
# Path values must be URL-encoded; query string excludes the leading question mark.
url="${HD_BASE_URL:?Set API origin}/v1/partner/webhook-endpoints/${HD_PATH_ENDPOINT_ID:?Set the path fixture}/test/${HD_QUERY_STRING:+?${HD_QUERY_STRING}}"
printf 'Accept: application/json\n' > "${HD_REQUEST_HEADERS_FILE:?Private header file}"
printf 'Authorization: Bearer %s\n' "${HD_PARTNER_API_KEY:?Set partner API key}" >> "$HD_REQUEST_HEADERS_FILE"
curl --silent --show-error --max-time 30 --request POST \
--header "@$HD_REQUEST_HEADERS_FILE" \
--dump-header "${HD_HEADERS_FILE:?Private response header file}" \
--output "${HD_RESPONSE_FILE:?Private response file}" \
--write-out '%{http_code}\n%{content_type}\n' \
"$url"import os, json
from pathlib import Path
from urllib.parse import quote
import requests
os.umask(0o077)
url = os.environ["HD_BASE_URL"].rstrip("/") + '/v1/partner/webhook-endpoints/{endpoint_id}/test/'
url = url.replace('{endpoint_id}', quote(os.environ['HD_PATH_ENDPOINT_ID'], safe=""))
if os.environ.get("HD_QUERY_STRING"): url += "?" + os.environ["HD_QUERY_STRING"]
headers = {"Accept": 'application/json'}
headers["Authorization"] = "Bearer " + os.environ["HD_PARTNER_API_KEY"]
kwargs = {}
response = requests.request('POST', url, headers=headers, timeout=30, allow_redirects=False, **kwargs)
Path(os.environ["HD_RESPONSE_FILE"]).write_bytes(response.content)
Path(os.environ["HD_HEADERS_FILE"]).write_text(json.dumps(dict(response.headers)))
print(response.status_code)
print(response.headers.get("Content-Type", ""))
import { readFileSync, writeFileSync } from "node:fs";
const env = process.env;
let url = env.HD_BASE_URL.replace(/\/$/, "") + "/v1/partner/webhook-endpoints/{endpoint_id}/test/";
url = url.replace("{endpoint_id}", encodeURIComponent(env.HD_PATH_ENDPOINT_ID));
if (env.HD_QUERY_STRING) url += "?" + env.HD_QUERY_STRING;
const headers = { "Accept": "application/json" };
headers.Authorization = "Bearer " + env.HD_PARTNER_API_KEY;
const options = { method: "POST", headers, redirect: "manual", signal: AbortSignal.timeout(30000) };
const response = await fetch(url, options);
writeFileSync(env.HD_RESPONSE_FILE, Buffer.from(await response.arrayBuffer()), {mode: 0o600});
writeFileSync(env.HD_HEADERS_FILE, JSON.stringify(Object.fromEntries(response.headers)), {mode: 0o600});
console.log(response.status);
console.log(response.headers.get("content-type") ?? "");
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/",
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.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/"
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.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hi-doctor.ai/v1/partner/webhook-endpoints/{endpoint_id}/test/")
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{
"id": "6e5d4c3b-2a19-4807-b6a5-948372615049",
"object": "webhook_delivery",
"endpoint_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"event_id": "2b3c4d5e-6f70-4182-93a4-b5c6d7e8f901",
"event_type": "endpoint.test",
"status": "pending",
"attempt_count": 0,
"next_attempt_at": "2026-11-03T12:40:00Z",
"last_attempt_at": null,
"delivered_at": null,
"response_status": null,
"response_excerpt": "",
"error": "",
"created_at": "2026-11-03T12:40:00Z"
}Authorizations
Partner API key sent as Authorization: Bearer . Test keys and live keys are separate.
Headers
Accepted but not used for replay on this operation. Only POST /v1/partner/consultations stores and replays responses by Idempotency-Key.
^[A-Za-z0-9_-]{8,128}$Path Parameters
The webhook endpoint id.
Response
The queued delivery.
The delivery id.
Always webhook_delivery.
webhook_delivery The webhook endpoint the delivery is for.
The event id. A replay keeps the same id; use it to deduplicate.
The event type, for example consultation.approved.
pending, succeeded, failed or exhausted.
pending, succeeded, failed, exhausted Delivery attempts made so far.
When the next attempt is due. Never null: it keeps the last scheduled time after a success or once retries are exhausted.
When the last attempt was made; null before the first attempt.
When the endpoint accepted the delivery; null until then.
HTTP status your endpoint returned on the last attempt; null if none was received.
The start of your endpoint's last response body; an empty string when none.
Why the last attempt failed; an empty string when it did not fail.
When the delivery was queued.