Webhooks
Webhooks let you subscribe to events in your environment and receive real-time HTTP POST notifications at a URL you specify. Use webhooks to sync data, trigger workflows, or build integrations without polling the API.
How It Works
Section titled “How It Works”- You create a webhook with a destination URL and a list of events to subscribe to
- When a subscribed event occurs, Paylent sends an HTTP POST request to your URL
- The request includes a JSON payload describing the event and a signature header for verification
- Failed deliveries are retried up to 5 times with exponential backoff
Creating a Webhook
Section titled “Creating a Webhook”Via the Dashboard
Section titled “Via the Dashboard”Navigate to Webhooks in the sidebar. Click Create Webhook, enter a name, URL, and select the events you want to receive.
Via the Management API
Section titled “Via the Management API”curl -X POST https://acme-test.paylent.com/api/webhooks \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/vnd.api+json" \ -d '{ "data": { "type": "webhook", "attributes": { "name": "User sync", "url": "https://myapp.example.com/webhooks/paylent", "events": ["user.created", "user.updated"] } } }'The response includes the signing_secret in plaintext. Save this immediately — it cannot be retrieved again.
Event Types
Section titled “Event Types”| Event | Description |
|---|---|
user.created | A user was created via the API |
user.registered | A user registered through the login flow |
user.updated | A user’s profile was updated |
user.password_reset | A user’s password was reset |
user.password_changed | A user changed their password |
role.created | A role was created |
role.updated | A role was updated |
permission.created | A permission was created |
permission.updated | A permission was updated |
client.registered | An OAuth client was registered |
client.updated | An OAuth client was updated |
token.issued | An access token was issued |
signing_key.generated | A new signing key was generated |
signing_key.deactivated | A signing key was deactivated |
environment.updated | An environment’s settings were updated |
custom_domain.created | A custom domain was added |
custom_domain.deleted | A custom domain was removed |
Payload Format
Section titled “Payload Format”Every webhook delivery is an HTTP POST with a JSON body:
{ "event": "user.created", "event_id": "evt_...", "timestamp": "2026-02-26T12:00:00Z", "environment_id": "env_...", "data": { "id": "usr_...", "first_name": "Jane", "last_name": "Doe" }}Request Headers
Section titled “Request Headers”Each delivery includes these headers:
| Header | Value |
|---|---|
Content-Type | application/json |
X-Paylent-Signature | sha256=<hex> |
X-Paylent-Event | The event type (e.g. user.created) |
User-Agent | Paylent-Webhook/1.0 |
Verifying Signatures
Section titled “Verifying Signatures”Every webhook delivery is signed with your webhook’s signing secret using HMAC-SHA256. Always verify the signature before processing the payload.
import crypto from "crypto";
function verifyWebhook(rawBody, signatureHeader, secret) { const expected = crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex");
const received = signatureHeader.replace("sha256=", ""); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(received) );}import hmacimport hashlib
def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool: expected = hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() received = signature_header.replace("sha256=", "") return hmac.compare_digest(expected, received)Retries
Section titled “Retries”If your endpoint returns a non-2xx status code or is unreachable, Paylent retries the delivery up to 5 times with exponential backoff. Each attempt is logged with the request payload, response status, response body, and duration.
You can view delivery history in the dashboard by clicking on a webhook and opening the Deliveries tab.
Rotating the Signing Secret
Section titled “Rotating the Signing Secret”If your signing secret is compromised, rotate it:
curl -X PATCH https://acme-test.paylent.com/api/webhooks/WEBHOOK_ID/rotate_secret \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/vnd.api+json"The new secret is returned in the response. Update your verification code with the new secret. Deliveries in-flight may still use the old secret, so consider accepting both secrets briefly during rotation.
Testing
Section titled “Testing”You can send a test delivery from the dashboard to verify your endpoint is configured correctly. The test event uses the type webhook.test with a sample payload.