Package Webhooks
Pkgly can deliver outbound HTTP webhooks when packages are published or deleted. Webhooks are configured from Admin → System → Package Webhooks and are dispatched asynchronously so package operations do not wait for the remote endpoint.
Supported events
package.publishedpackage.deleted
Pkgly emits one webhook per logical package action. It does not emit for rejected writes, missing/no-op deletes, proxy cache maintenance, or failed package operations.
Delivery model
- Method:
POST - Body: fixed JSON payload
- Headers: optional custom headers per webhook
- Queue: durable Postgres-backed delivery table
- Retry policy: 5 total attempts
- Backoff: 1, 2, 4, then 8 minutes between retries
- Retry conditions: timeouts, transport failures, and HTTP
5xx - Terminal failure: HTTP
4xxor exhausted retries
Deliveries are at-least-once. If the process crashes after the remote endpoint receives a payload but before Pkgly marks the row complete, the worker may retry the same delivery after the claim lease expires.
Secret headers
Header values are stored server-side and treated as write-only secrets.
- Reads return header names plus a
configuredflag. - The UI never receives existing header values back.
- Leaving a configured header value blank during edit preserves the stored secret.
- Removing a header from the form deletes it from future deliveries, but already-queued jobs keep the header snapshot they were created with.
Payload format
Each delivery uses an Artifactory-style envelope:
{
"domain": "package",
"event_type": "package.published",
"event_id": "2fa6f796-9c0b-4f72-8f8f-a1cb1f7c0e4d",
"occurred_at": "2026-04-22T10:00:00Z",
"subscription_key": "f38d0ec1-9e9e-4d6f-8f42-3f0c0e70d1af",
"source": {
"application": "pkgly",
"version": "3.0.0-BETA"
},
"data": {
"actor": {
"id": 1,
"username": "admin"
},
"repository": {
"id": "2d3d9b6a-6c6d-45aa-8ac3-9f5b4f6d9d4a",
"name": "npm-hosted",
"storage_name": "primary",
"format": "npm"
},
"storage": {
"name": "primary"
},
"package": {
"scope": "acme",
"key": "@acme/example",
"name": "example",
"version": "1.2.3",
"project_path": "packages/acme/example",
"version_path": "packages/acme/example/1.2.3",
"canonical_path": "packages/acme/example/1.2.3/example-1.2.3.tgz",
"reference": "1.2.3"
}
}
}subscription_key is the webhook definition ID so downstream systems can identify which subscription triggered the delivery.
Operational expectations
- Editing a webhook affects only new deliveries.
- Deleting a webhook removes the definition but does not rewrite jobs already queued.
- Delivery status shown in the UI reflects the latest queued/attempted job for that webhook.
- If a destination is unavailable, package publish/delete requests still succeed as long as the package action itself succeeded.