feat: align sdk with current convoy api and harden webhook verification#35
Merged
Conversation
adds endpoint pause, broadcast events, event replay, and event delivery forceResend. batchResend now posts an empty body with query filters to match the server contract (it previously used PUT with a body the server ignored). client config now requires uri, rejects project-scoped uris, and pins X-Convoy-Version to 2025-11-24. transport errors are rethrown as-is instead of being mislabelled as internal server errors, and event.create rejects a missing endpoint_id with a clear ConfigException instead of a raw TypeError. webhook verification fix: advanced signature header pairs are now classified by key instead of value shape, so a purely numeric signature is no longer mistaken for the timestamp and valid multi-signature headers verify. adds route contract tests via mocked axios plus regression tests for the header parsing and create-validation fixes.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 18f91af. Configure here.
axios transport errors carry the request config, including the Authorization header, so rethrowing them raw could leak the api key into downstream exception logs. delete config and request from the error before rethrowing; message and code are preserved. regression test asserts the rethrown error has neither field.
t=Infinity passed the NaN check and made timestampAge -Infinity, bypassing the expiry check; the timestamp must now be finite. events.create now requires endpoint_id to be a non-empty string so an empty array no longer slips past the falsy check. both from bugbot review, with regression tests.
motunrayokoyejo
approved these changes
Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
pause,createBroadcastEvent, eventreplay, and event deliveryforceResend.batchResendnow posts an empty body with query filters, matching the server contract (previously PUT with a body the server ignored).uri, rejects project-scoped URIs (prevents double-scoped URLs), and pinsX-Convoy-Versionto2025-11-24. Transport errors (e.g.ECONNREFUSED) are rethrown as-is instead of being mislabelled asServerException: Internal Server Error, andevents.createthrows a clearConfigExceptionwhenendpoint_idis missing instead of a rawTypeError.t=vsv1=) instead of value shape, so a purely numeric signature value is no longer mistaken for the timestamp and valid multi-signature headers verify correctly. StrictNumber()parsing keeps malformed timestamps liket=2202-1-1rejected.ExpireSecret.secretis now optional (the server generates it when omitted). README updated for the current API.Breaking changes
uriis a required config value and must be the instance base (e.g.https://us.getconvoy.cloud/api/v1), not a project path.batchResendtakes query filters only; useforceResendfor id-based retries.Test plan
npm test(33 tests: config, webhook vectors, route contracts via mocked axios, regression tests for header parsing and create validation),tsc --noEmitcleanNote
Medium Risk
Breaking
urirequirement andbatchResendsignature affect all integrators; webhook parsing changes fix security bugs but alter verification outcomes for edge-case headers.Overview
1.2.0 aligns the JS SDK with the current Convoy API and tightens client and webhook behavior, with breaking config and delivery-retry changes.
Client configuration now requires an instance
uri(no default cloud URL), rejects URIs that already include/projects, and sendsX-Convoy-Version: 2025-11-24. Transport failures without an HTTP response are rethrown as-is (with axiosconfig/requeststripped so auth does not leak into logs) instead of being wrapped as internal server errors.New API surface: endpoint
pause, eventscreateBroadcastEventandreplay, and deliveryforceResend.batchResendis a breaking change: it is now POST with an empty body and filters in query params only; ID-based force retries useforceResend.events.createvalidatesendpoint_idas a non-empty string.ExpireSecret.secretis optional in types.Webhook verification parses advanced headers by key (
t=vs signatures), rejects non-finite timestamps, and fixes misclassification of numeric-looking signature values.README and tests document the new setup URLs, broadcast example, and route contracts.
Reviewed by Cursor Bugbot for commit 2243b2f. Bugbot is set up for automated code reviews on this repo. Configure here.