Webhooks
React to events in your packages and automate workflows with webhooks.
Overview
Webhooks allow you to receive near real-time notifications when certain events occur in your packages.
You can use them to automate tasks like triggering custom workflows when a new version of your package is published, or when somebody purchases a license for a package.
Webhooks are available to Privato users on the Growth and Scale plans.
Events
You can create webhooks for the following events:
license.created– Fired when a license is created.license.updated– Fired when a license is updated.license.deleted– Fired when a license is deleted.release.published– Fired when a new release is published.package.created– Fired when a new package is created.package.updated– Fired when a package is updated.package.deleted– Fired when a package is deleted.customer.created– Fired when a new customer is created.customer.updated– Fired when a customer is updated.package.downloaded– Fired when a package is downloaded.
Creating a webhook
To create a webhook, navigate to the "Webhooks" section inside of the Privato dashboard and click on the "Create webhook" button.
Each webhook must have a name, destination URL, and at least 1 event associated with it.
The destination URL is the URL that will receive the webhook payload when an event occurs. The request that
Privato sends will be a POST request
with a JSON body containing details about the event that occurred, e.g. the package created, the license
updated, etc.
Securing your webhooks
All webhooks sent from Privato are sent with a unique "signing secret" inside of the
X-Signature header. This can be used to verify that the incoming request is actually
from Privato and not from a malicious third party.
After creating your webhook, you can find the signing secret by viewing the webhook details in the Privato
dashboard. You should then use this to secure your webhook
endpoint by verifying the signature received in the X-Signature header against the payload of
the request using the signing secret.
Here's an example of how to verify the signature using PHP inside of an imaginary Laravel application.
public function __invoke(Request $request)
{
$secret = config('services.privato.signing_secret');
$payload = $request->getContent();
$hash = hash_hmac('sha256', $payload, $secret);
if (! hash_equals($hash, $request->header('X-Signature'))) {
abort(401);
}
}
Payloads
Each event has a specific payload structure that is sent in the body of the webhook request.
License
{
"id": 1,
"key": "ABC123-DEF456-GHI789",
"short_key": "ABC123",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"package": {
"id": 1,
"name": "Example Package",
"slug": "example-package",
"description": "This is an example package.",
"repository": "vendor/package",
"composer_name": "vendor/package",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
},
"customer": {
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"marketing_consent": true,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
}
Customer
{
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"marketing_consent": true,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
Package
{
"id": 1,
"name": "Example Package",
"slug": "example-package",
"description": "This is an example package.",
"repository": "vendor/package",
"composer_name": "vendor/package",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
Release
{
"id": 1,
"name": "v1.0.0",
"body": "Initial release",
"number_of_files": 2,
"size_in_bytes": 1024,
"published_at": "2024-01-01T00:00:00Z",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"package": {
"id": 1,
"name": "Example Package",
"slug": "example-package",
"description": "This is an example package.",
"repository": "vendor/package",
"composer_name": "vendor/package",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
}
Failed deliveries
If a webhook delivery fails because the destination URL did not respond with a 2xx code, Privato will automatically retry the delivery.
The first retry will be performed 10 seconds after the initial failed attempt, and the second retry will be performed 100 seconds after that.
If the second retry also fails, the webhook delivery will completely fail and Privato will stop trying to deliver that webhook.