openai/openai-python · error · InvalidWebhookSignatureError
Invalid webhook timestamp format
Error message
Invalid webhook timestamp format
What it means
webhook_signature_matches validates signed webhook payloads. The webhook-timestamp header must be an integer Unix timestamp; a non-numeric value raises InvalidWebhookSignatureError('Invalid webhook timestamp format').
Source
Thrown at src/openai/lib/_webhooks.py:29
def webhook_signature_matches(
payload: str | bytes,
headers: HeadersLike,
*,
secret: str,
tolerance: int,
) -> bool:
"""Validate the replay window and compare the supplied signatures."""
signature_header = get_required_header(headers, "webhook-signature")
timestamp = get_required_header(headers, "webhook-timestamp")
webhook_id = get_required_header(headers, "webhook-id")
# Validate timestamp to prevent replay attacks
try:
timestamp_seconds = int(timestamp)
except ValueError:
raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None
now = int(time.time())
if now - timestamp_seconds > tolerance:
raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None
if timestamp_seconds > now + tolerance:
raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None
# Extract signatures from v1,<base64> format
# The signature header can have multiple values, separated by spaces.
# Each value is in the format v1,<base64>. We should accept if any match.
signatures: list[str] = []
for part in signature_header.split():
if part.startswith("v1,"):
signatures.append(part[3:])
else:
signatures.append(part)View on GitHub (pinned to 9917c6e28e)
Solutions
- Send the timestamp as Unix epoch seconds (e.g. '1709049600')
- Log the raw webhook-timestamp header at your ingress to confirm what arrives
- Ensure proxies do not mutate or strip webhook-* headers
Example fix
# before
headers = {"webhook-timestamp": "2024-01-01T00:00:00Z", ...}
# after
headers = {"webhook-timestamp": "1704067200", ...} Defensive patterns
Strategy: try-catch
Validate before calling
def valid_ts(headers) -> bool:
try:
int(get_required_header(headers, "webhook-timestamp"))
return True
except (ValueError, KeyError):
return False Try / catch
try:
ok = webhook_signature_matches(body, headers, secret)
except InvalidWebhookSignatureError as e:
if "timestamp format" in str(e):
return Response(400)
raise Prevention
- Send webhook timestamps as epoch seconds
- Verify proxies pass webhook-* headers unmodified
- Log raw headers for incoming webhooks
When it happens
Trigger: A request where the webhook-timestamp header is missing-numeric content (e.g. an ISO date string, empty, or corrupted by a proxy that rewrites headers).
Common situations: Proxies/LBs rewriting or dropping webhook headers; senders using ISO-8601 instead of epoch seconds; test fixtures with placeholder timestamps.
Related errors
- Webhook timestamp is too new
- Pagination is only supported with mappings
- No next page expected; please check `.has_next_page()` befor
- max_retries cannot be None. If you want to disable retries,
- Unexpected JSON data type, {type(json_data)}, cannot merge w
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/695c0dc36b94786d.
Report an issue: GitHub.