Every webhook delivery from Projul AI Connect is signed with your endpoint's secret (prjl_whsec_...), so your endpoint can confirm a message came from Projul and was not altered.
This is for whoever builds the receiving endpoint. Registering it is covered in How do I get notified when something changes in Projul?.
Verifying deliveries
The body is a JSON envelope: id (evt_...), type such as task.updated (full list in Webhook Event Types: A Complete Breakdown), created_at, api_version (v1), and data. Projul-Event-Id and Projul-Event-Type repeat those two for routing before you parse; User-Agent is Projul-Connect/1.0. Projul-Signature looks like t=1756920000,v1=5f2a…: t is the attempt's Unix time, v1 a lowercase hex HMAC-SHA256.
- Take the raw request bytes, before any JSON parsing, and the header's t value.
- Compute HMAC-SHA256 of "t.raw_body" with your prjl_whsec_ secret, as lowercase hex.
- Compare it to every v1 element in the header with a constant-time comparison; any match is valid.
- Reject the delivery if t is more than five minutes from your clock, even if it matches.
Ignore any header element you do not recognise; Projul may add more over time.
Rotating the secret
POST /v1/webhook_endpoints/{id}/rotate_secret returns a new secret once. For 24 hours the old one still verifies and deliveries carry both v1 elements, so switch over in that window; after it, only the new secret works, and at most two are ever active.
Duplicates and ordering
Deliveries are at least once and unordered. A retry or replay keeps the event id but gets a new Projul-Delivery-Id, so dedupe on the event id, not a body hash: data is rebuilt each send and can differ between deliveries. Use updated_at, or read the record back, when order matters; a converted lead raises both project.updated and project.converted.
Responding and keeping the secret safe
Answer with a 2xx once stored, then do the work after. Projul retries up to 10 attempts over 10 seconds each, disabling an endpoint only after 20 straight failures spanning 24 hours, emailing your account when it does. A 401 for a bad signature or 400 for a bad body still counts as a failure and is retried the same way.
Store the secret in your secret store, not shared code or config, and never log it or a failed message's body. Projul only registers https addresses; rotate if you think it has leaked.
Questions? Let's Chat.
support@projul.com
(844) 776-5853