ComposioHQ/composio · error · ComposioWebhookPayloadError
Invalid webhook timestamp: ${webhookTimestamp}. Expected Uni
Error message
Invalid webhook timestamp: ${webhookTimestamp}. Expected Unix timestamp in seconds. What it means
The 'webhook-timestamp' header could not be parsed as an integer Unix timestamp in seconds (parseInt yields NaN). The timestamp is needed both for the HMAC payload and for the replay-tolerance check, so a non-numeric value is rejected with ComposioWebhookPayloadError before any crypto work.
Source
Thrown at ts/packages/core/src/models/Triggers.ts:1304
}
}
if (!isValid) {
throw new ComposioWebhookSignatureVerificationError(
'The signature provided is invalid. Please ensure you are using the correct webhook secret.'
);
}
}
/**
* Validates that the webhook timestamp is within the allowed tolerance
* @private
*/
private validateWebhookTimestamp(webhookTimestamp: string, tolerance: number): void {
const timestampSeconds = parseInt(webhookTimestamp, 10);
if (Number.isNaN(timestampSeconds)) {
throw new ComposioWebhookPayloadError(
`Invalid webhook timestamp: ${webhookTimestamp}. Expected Unix timestamp in seconds.`
);
}
const webhookTimeMs = timestampSeconds * 1000;
const currentTime = Date.now();
const timeDifference = Math.abs(currentTime - webhookTimeMs);
if (timeDifference > tolerance * 1000) {
throw new ComposioWebhookSignatureVerificationError(
`The webhook timestamp is outside the allowed tolerance. ` +
`The webhook was sent ${Math.round(timeDifference / 1000)} seconds ago, ` +
`but the maximum allowed age is ${tolerance} seconds.`
);
}
}
}
View on GitHub (pinned to 64b1b85502)
Solutions
- Pass the header value through unmodified — Composio always sends epoch seconds as a string
- In tests, generate Math.floor(Date.now()/1000).toString()
- Return 400 early for requests whose webhook-timestamp is not a digit-only string
- Check for middleware that rewrites header values
Example fix
// before const ts = new Date().toISOString(); // wrong format // after const ts = Math.floor(Date.now() / 1000).toString();
Defensive patterns
Strategy: validation
Validate before calling
const ts = String(req.headers['webhook-timestamp'] ?? '');
if (!/^\d+$/.test(ts)) return res.status(400).send('Bad webhook-timestamp'); Type guard
const isUnixSeconds = (v: unknown): v is string => typeof v === 'string' && /^\d{10}$/.test(v); Try / catch
try { verifyWebhookSignature(...); } catch (e) { if (e instanceof ComposioWebhookPayloadError) return res.status(400).end(); throw e; } Prevention
- Pass header values through unmodified
- Use epoch-seconds strings in fixtures
- Early-reject non-digit timestamp headers
When it happens
Trigger: Passing a timestamp like '2024-01-01T00:00:00Z', an ISO string, milliseconds with a trailing unit ('1700000000000ms'), an empty-ish/garbage string that survived the earlier length check, or a value corrupted by header encoding.
Common situations: Test fixtures using ISO dates instead of epoch seconds, transforming the header before verification, or non-Composio clients sending arbitrary header values to your endpoint.
Related errors
- Invalid parameters passed to set webhook subscription
- No webhook ID was provided. Please pass the value of the 'we
- No webhook timestamp was provided. Please pass the value of
- No valid v1 signature found in the webhook-signature header.
- The signature provided is invalid. Please ensure you are usi
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/13dc06df60c68ea2.
Report an issue: GitHub.