📩Webhooks
Webhooks let DevPayr tap your backend on the shoulder and say, “Hey, something just changed — you may want to react.”
Instead of polling DevPayr for updates, you give us an HTTPS endpoint and we send signed JSON requests whenever important events happen on your projects, licenses, or domains.
Common things you might do with webhooks:
Activate or lock a user’s account after a license is created or suspended
Sync project/domain changes into your own admin panel
Trigger emails or notifications when a project is marked as paid
Keep your billing system and DevPayr in sync without manual work
1. Where to Configure Webhooks
You can define a webhook endpoint in two places:
a) Account-level webhook (profile / settings)
From your DevPayr dashboard:
Go to Settings → Account
Set your Webhook Endpoint — e.g.
https://yourapp.com/devpayr/webhooks
This acts as a fallback URL used by all projects that don’t have their own project-level webhook.

b) Project-level webhook
When creating or editing a project (see the “Create New Project” screen):
In Integration / Webhook Settings, set:
Project Webhook URL – where this project’s webhooks should be sent
Webhook Secret – a secret string used to sign payloads (more on this below)
If a project has its own Project Webhook URL, that URL is used instead of the profile-level one.

Rule of thumb
Project Webhook URL set? → use that
Otherwise → use profile-level webhook URL
If neither exists → no webhooks are sent for that project
2. Events DevPayr Sends
DevPayr sends webhooks for changes around projects, domains, and licenses.
Each webhook payload has this general structure:
And every request includes helpful HTTP headers (explained in the next section).
Project-level events
These events help you keep your own system in sync with what’s happening to a project.
project.createdFired when a new project is created in DevPayr.project.updatedFired when key project fields change (name, slug, description, logo, redirect URL, meta, etc.).project.paid_status_toggledFired whenever the has_paid flag on a project is turned on or off. Useful if you treat “has_paid = false” as “lock this product”.
Project domain events
These events are about domains attached to a project.
project.domain.addedA domain has been added to the project (including environment, whether it’s primary, verified, etc.).project.domain.deletedA domain has been removed from the project.project.domain.environment_updatedThe domain’s environment changed (e.g., fromstagingtoproduction).project.domain.primary_setA domain has been set as the primary domain for the project.
License events
These events track the lifecycle of a license and the domains attached to it.
license.createdA new license was created for a project.license.suspendedA license was suspended / revoked (you’ll usually want to lock the user here).license.reactivatedA previously suspended license is re-enabled.license.domain.addedA new domain has been attached/learned for that license (license-level domain mode).license.domain.removedA domain has been detached from that license.
You don’t need to memorize all of these — your endpoint will always receive the event name in the payload and in a header so you can switch on it.
3. Request Format & Headers
Every webhook delivery is:
An HTTP POST
With
Content-Type: application/jsonCarrying the JSON payload described above
In addition, DevPayr includes a few headers to help you route and verify the request:
X-Webhook-Event– the event name (e.g.license.created)X-Project-ID– the numeric ID of the project firing the eventX-License-ID– present for license-related events (license created / suspended / etc.)X-Signature– HMAC-SHA256 signature of the JSON payload using your project’s Webhook Secret
Tip
If you don’t set a Webhook Secret on the project, X-Signature will be empty.
For production systems, always set a secret and verify every request.
4. Example Payloads
These examples show the shape of the data you’ll receive. Field names may grow over time, but the structure remains similar.
4.1 project.created
project.createdYou can use this to auto-create a matching record in your own database.
4.2 project.paid_status_toggled
project.paid_status_toggledTypical reaction in your system:
has_paid = true→ unlock the software, enable premium featureshas_paid = false→ schedule a downgrade, show a “payment required” message, etc.
4.3 license.created
license.createdYou might:
Attach this license to the customer record in your own DB
Trigger a “Your license is ready” email with the masked key
Start a provisioning job for the customer’s environment
4.4 license.suspended
license.suspendedTypical reactions:
Mark the customer’s subscription as “suspended”
Lock logins or reduce features in your app
Show an in-app banner telling them to contact billing or renew
4.5 project.domain.added
project.domain.addedYou could:
Log this domain in your control panel
Use it to configure routing, SSL, or DNS automation in your own infra
4.6 license.domain.added
license.domain.addedIf you use DevPayr’s license-level domain tracking, this lets you see where a license is being activated.
5. Verifying the Signature
To make sure a webhook really came from DevPayr and not from a random script, you should verify the X-Signature header using your Webhook Secret.
The logic is:
Take the raw JSON body exactly as received.
Compute
HMAC-SHA256(body, webhook_secret)Compare that value to the
X-Signatureheader (constant-time compare if possible).If they don’t match, reject the request.
Example – Node.js (Express)
Example – PHP (generic)
You can adapt the same pattern in any language that supports HMAC-SHA256.
Tip
Always respond quickly (just
200 OK) and push heavy work (emails, database tasks, external API calls) to a background job or queue. Webhooks should be treated like fire alarms — acknowledge fast, handle details in the background.
6. Best Practices
To get the most out of DevPayr webhooks:
Always use HTTPS for your webhook endpoint.
Set a Webhook Secret for each project and verify
X-Signatureon every request.Use project-level webhooks when different projects need to hit different systems.
Log incoming webhooks on your side while integrating — it makes debugging far easier.
Make processing idempotent (don’t double-process the same event if your endpoint is called twice). Using a combination of
event+ resource ID + timestamp is usually enough.Return a 2xx status code once you’ve accepted the event. Non-2xx means “delivery failed”.
Once your webhook endpoint is wired up, DevPayr becomes much more than “just a license check”. Your own systems will be able to react in real-time whenever licenses, domains, or project billing status change — without you writing extra cron jobs or manual sync scripts.
Last updated