- The public HTTP API client is generated from Convoy's OpenAPI spec (
docs/v3/openapi3.yaml) via openapi-python-client. - Webhook signature verification stays hand-written. Generators do not own crypto.
src/convoy/utils/webhook.pyand the sharedtest/signature-vectors.jsoncontract remain the source of truth for verify. The generation sync script (scripts/generate.sh) never touchessrc/convoy/utils/.
Generation originally bootstrapped on Speakeasy, but the Speakeasy free tier allows one generated SDK per workspace and convoy.js holds that slot. The Speakeasy pipeline is kept dormant (.speakeasy/, .genignore, .github/workflows/speakeasy_generation.yaml) so the provider can be switched back without a rebuild; the active pipeline is openapi-python-client (.github/workflows/sdk_generation.yaml).
Shipping the generated client is an intentional 1.x break from the hand-written 0.x surfaces. Method shapes are not silently preserved.
- This PR wires openapi-python-client generation; the hand-written HTTP client stays removed and verify lives at
src/convoy/utils/webhook.py(inside the generated module tree, sofrom convoy.utils.webhook import Webhookkeeps resolving —package_name_override: convoyin.openapi-python-client.yml). - The first
sdk_generation.yamlrun opens a PR that adds the OpenAPI-generated client and publishes as1.x. - Consumers pin
0.xuntil they migrate call sites.
from convoy.utils.webhook import Webhook
webhook = Webhook(secret="endpoint-secret")
payload = request.body.decode("utf-8")
signature = request.headers.get("X-Convoy-Signature", "")
if not webhook.verify_signature(payload, signature):
raise PermissionError("invalid signature")CI on frain-dev/convoy dispatches sdk_generation.yaml when OpenAPI artifacts change. Locally:
pip install openapi-python-client==0.29.0 ruff==0.15.22
./scripts/generate.sh