Skip to content

Releases: frain-dev/convoy-python

v1.0.0a1

v1.0.0a1 Pre-release
Pre-release

Choose a tag to compare

@mekilis mekilis released this 21 Jul 13:26

What's new

  • OpenAPI-generated API client (AuthenticatedClient + convoy.api.*) via openapi-python-client
  • Hand-written webhook verification unchanged at convoy.utils.webhook (fail-closed bool)
  • Requires Python 3.11+

Install (pre-release)

pip install --pre convoy-python
# or
pip install convoy-python==1.0.0a1

Plain pip install convoy-python still resolves to 0.2.0 until a final 1.0.0 is cut.

Migration: 0.2.0 → 1.0.0

1.0.0 is a full rewrite. The hand-written client is removed and replaced with a client generated from Convoy's OpenAPI spec via openapi-python-client. Webhook signature verification remains hand-written at the same import path, with a stricter, fail-closed contract.

The first release is published as a pre-release (1.0.0a1), so plain pip install convoy-python keeps resolving to 0.2.0 until a final 1.0.0 is cut. Install the pre-release explicitly.

Breaking changes

  • Python 3.11 or newer is required. 0.2.0 ran on any Python 3.
  • Dependencies changed from requests to httpx and attrs.
  • The Convoy facade class is gone. There is no from convoy import Convoy anymore. You construct an AuthenticatedClient and call per-operation module functions.
  • Client construction and auth. 0.2.0 took a config dict with api_key, uri, and project_id (and documented but effectively unused username/password basic auth keys, which are dropped entirely). 1.0.0 uses AuthenticatedClient(base_url=..., token=...). The base URL no longer includes /v1 and no longer embeds the project ID; generated paths look like /v1/projects/{project_id}/..., so pass the instance API root, for example https://us.getconvoy.cloud/api.
  • Project ID moved from the client to each call. Every operation takes project_id as its first argument.
  • Methods are now module-level functions, not attribute methods. convoy.event.create(query, data) style calls are replaced by from convoy.api.events import create_endpoint_event; create_endpoint_event.sync(project_id, client=client, body=...). Each operation module exposes four callables: sync, sync_detailed, asyncio, and asyncio_detailed. Async support is new in 1.0.0.
  • Requests and responses are typed attrs models, not dicts and tuples. 0.2.0 returned (json_dict, status_code) tuples. 1.0.0 sync/asyncio return a parsed model for the documented status codes (for example CreateEndpointEventResponse201); sync_detailed/asyncio_detailed return a Response object with status_code, content, headers, and parsed. Build request bodies with model classes such as convoy.models.ModelsCreateEvent.
  • The group API is gone. Server-side, groups became projects; use the functions under convoy.api.projects.
  • batchresend no longer exists under that name. Use convoy.api.event_deliveries.batch_retry_event_delivery (filters are query parameters) or force_resend_event_deliveries (takes a body of IDs).
  • Webhook verification fails closed and returns a strict bool. In 0.2.0, verify_signature could return a truthy error-message string on failure, which made if webhook.verify_signature(...) pass for invalid signatures. In 1.0.0 it returns True or False, never a string, and malformed input returns False instead of raising unexpected errors. If you relied on inspecting returned error strings, switch to a plain boolean check. Supported hash algorithms are now restricted to sha256 and sha512 (the only algorithms Convoy signs with); passing md5, sha1, or other algorithms now raises ValueError.

Method mapping

0.2.0 1.0.0 (call .sync(...) or .asyncio(...))
convoy.endpoint.all(query) convoy.api.endpoints.get_endpoints
convoy.endpoint.create(query, data) convoy.api.endpoints.create_endpoint
convoy.endpoint.find(id, query) convoy.api.endpoints.get_endpoint
convoy.endpoint.update(id, query, data) convoy.api.endpoints.update_endpoint
convoy.endpoint.delete(id, query, data) convoy.api.endpoints.delete_endpoint
convoy.event.all(query) convoy.api.events.get_events_paged
convoy.event.create(query, data) convoy.api.events.create_endpoint_event
convoy.event.find(id, query) convoy.api.events.get_endpoint_event
convoy.event_delivery.all(query) convoy.api.event_deliveries.get_event_deliveries_paged
convoy.event_delivery.find(id, query) convoy.api.event_deliveries.get_event_delivery
convoy.event_delivery.resend(id, query) convoy.api.event_deliveries.resend_event_delivery
convoy.event_delivery.batchresend(id, query, data) convoy.api.event_deliveries.batch_retry_event_delivery
convoy.delivery_attempt.* convoy.api.delivery_attempts.get_delivery_attempts / get_delivery_attempt
convoy.source.* convoy.api.sources.*
convoy.subscription.* convoy.api.subscriptions.*
convoy.group.* convoy.api.projects.* (groups are now projects)
convoy.webhook convoy.utils.webhook.Webhook (same import path as before)

Before and after

Install:

# 0.2.0
pip install convoy-python

# 1.0.0 (pre-release)
pip install --pre convoy-python

Client setup:

# 0.2.0
from convoy import Convoy
convoy = Convoy({
    "api_key": "your_api_key",
    "uri": "https://us.getconvoy.cloud/api/v1",
    "project_id": "your_project_id",
})

# 1.0.0
from convoy import AuthenticatedClient
client = AuthenticatedClient(
    base_url="https://us.getconvoy.cloud/api",  # no /v1, no project id
    token="your_api_key",
)
project_id = "your_project_id"

Create an endpoint:

# 0.2.0
(response, status) = convoy.endpoint.create({}, {
    "name": "default-endpoint",
    "url": "https://example.com/webhooks/convoy",
    "secret": "endpoint-secret",
})
endpoint_id = response["data"]["uid"]

# 1.0.0
from convoy.api.endpoints import create_endpoint
from convoy.models import ModelsCreateEndpoint

result = create_endpoint.sync(project_id, client=client, body=ModelsCreateEndpoint(
    name="default-endpoint",
    url="https://example.com/webhooks/convoy",
    secret="endpoint-secret",
))
endpoint_id = result.data.uid

Send an event (sync and async):

from convoy.api.events import create_endpoint_event
from convoy.models import ModelsCreateEvent, ModelsCreateEventDataType0

body = ModelsCreateEvent(
    endpoint_id=endpoint_id,
    event_type="payment.success",
    data=ModelsCreateEventDataType0.from_dict({"status": "Completed"}),
)

# sync
result = create_endpoint_event.sync(project_id, client=client, body=body)

# async
result = await create_endpoint_event.asyncio(project_id, client=client, body=body)

List event deliveries:

# 0.2.0
(response, status) = convoy.event_delivery.all({"perPage": 20})

# 1.0.0
from convoy.api.event_deliveries import get_event_deliveries_paged

result = get_event_deliveries_paged.sync(project_id, client=client, per_page=20)
deliveries = result.data.content

Verify a webhook signature:

# import path unchanged
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):
    # reject the request; verify_signature now returns a strict bool
    ...

v0.2.0

Choose a tag to compare

@subomi subomi released this 16 May 10:13
47d5d59
Merge pull request #10 from frain-dev/subomi-patch-1

feat: add github actions to release new packages on tag

v0.1.1

Choose a tag to compare

@Youngestdev Youngestdev released this 12 Oct 09:56
3a6de49

What's Changed

New Contributors

Full Changelog: v0.1.0...v0.2.0

v0.1.0

Choose a tag to compare

@ogbanugot ogbanugot released this 14 Mar 16:48
remove secret field