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-deliveries/${HD_PATH_DELIVERY_ID:?Set the path fixture}/replay/${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-deliveries/{delivery_id}/replay/'
url = url.replace('{delivery_id}', quote(os.environ['HD_PATH_DELIVERY_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-deliveries/{delivery_id}/replay/";
url = url.replace("{delivery_id}", encodeURIComponent(env.HD_PATH_DELIVERY_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-deliveries/{delivery_id}/replay/",
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-deliveries/{delivery_id}/replay/"
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-deliveries/{delivery_id}/replay/")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hi-doctor.ai/v1/partner/webhook-deliveries/{delivery_id}/replay/")
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": "consultation.approved",
"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"
}Replay a delivery
Resets the existing delivery for a fresh schedule: status pending, attempt_count 0, next_attempt_at now and error cleared, with the same delivery id, event id and body. It does not create another delivery. A pending delivery a worker is sending right now is left unchanged. 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: Resets the existing delivery row so it is sent again on a fresh retry schedule; a delivery a worker is sending at that moment is left as it is.
Retries: Safe to repeat: each call resets the same delivery again and never creates another one; deduplicate by event id.
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-deliveries/${HD_PATH_DELIVERY_ID:?Set the path fixture}/replay/${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-deliveries/{delivery_id}/replay/'
url = url.replace('{delivery_id}', quote(os.environ['HD_PATH_DELIVERY_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-deliveries/{delivery_id}/replay/";
url = url.replace("{delivery_id}", encodeURIComponent(env.HD_PATH_DELIVERY_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-deliveries/{delivery_id}/replay/",
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-deliveries/{delivery_id}/replay/"
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-deliveries/{delivery_id}/replay/")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hi-doctor.ai/v1/partner/webhook-deliveries/{delivery_id}/replay/")
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": "consultation.approved",
"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 delivery id.
Response
The re-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.