NAME
Business::Payr::Webhook - class for verifying and parsing Payr webhook notifications.
SYNOPSIS
use Business::Payr::Webhook;
# In your webhook endpoint handler:
my $Webhook = Business::Payr::Webhook->new(
body => $raw_request_body, # raw POST body string
signature => $x_payr_signature_header, # X-Payr-Signature header value
secret => $webhook_secret, # your Payr webhook secret
);
# Signature is verified during construction - an exception is thrown
# if the signature does not match. Always wrap in eval / try:
my $Payment = eval { $Webhook->resource };
if ( $@ ) {
warn "Webhook verification failed: $@";
return http_response( 400 );
}
if ( $Payment->is_payment_success ) {
my $amount_gbp = $Payment->amount / 100;
printf "Received %.2f %s for student %s\n",
$amount_gbp, $Payment->currency, $Payment->student_ref;
if ( $Payment->schedule_activated ) {
printf "Schedule %s activated; next instalment: %s\n",
$Payment->schedule_id, $Payment->next_installment_date // 'N/A';
}
}
elsif ( $Payment->is_payment_failed ) {
warn sprintf "Payment %s failed (%s): %s\n",
$Payment->payment_id,
$Payment->error_code // 'unknown',
$Payment->error_message // 'no detail';
}
elsif ( $Payment->is_payment_pending ) {
warn "Payment " . $Payment->payment_id
. " is pending: " . ( $Payment->pending_reason // 'unknown reason' );
}
DESCRIPTION
Business::Payr::Webhook handles the receipt, cryptographic verification, and parsing of webhook notifications sent by the Payr platform.
All webhooks are signed with HMAC-SHA256 using a secret shared between Payr and your platform. The signature is carried in the X-Payr-Signature HTTP header. Verification is performed automatically during object construction; an exception is thrown if the signature is missing, incorrect, or the payload cannot be parsed.
Important: You should always pass the raw request body string as the body argument, before any deserialisation. Re-serialising a parsed structure may produce different byte sequences and will cause verification to fail.
Contact support@mypayr.co.uk to configure your webhook endpoint URL and receive your webhook secret.
SIGNATURE VERIFICATION DETAILS
Payr signs webhook payloads as follows:
The JSON payload is serialised with compact separators (no spaces) and lexicographically sorted keys.
An HMAC-SHA256 digest of the serialised payload is computed using the shared webhook secret.
The hex-encoded digest is placed in the
X-Payr-SignatureHTTP header.
This module computes the same digest over the raw request body and compares it against the header value using a constant-time comparison to prevent timing attacks.
DEBUGGING
Set MOJO_CLIENT_DEBUG=1 for user agent and transport debug output when fetching JWKS or other remote resources.
ATTRIBUTES
- body (Str, required)
-
The raw (undecoded) HTTP request body string exactly as received from Payr. Do not deserialise and re-serialise this value before passing it in; the signature is computed over the original byte sequence.
- signature (Str, required)
-
The value of the
X-Payr-SignatureHTTP header included in the webhook request. This is a hex-encoded HMAC-SHA256 digest. - secret (Str, required)
-
Your Payr webhook signing secret. Keep this value secure and never expose it in client-side code or version control. Contact support@mypayr.co.uk to obtain or rotate your secret.
METHODS
BUILD
Called automatically by Moose after construction. Verifies the HMAC-SHA256 signature and decodes the JSON payload. Throws an exception if either step fails.
You do not need to call this method directly.
event_type
Returns the event field from the decoded webhook payload.
my $type = $Webhook->event_type;
# "payment_success", "payment_failed", or "payment_pending"
is_payment_success
Returns 1 if this webhook represents a payment_success event, 0 otherwise.
if ( $Webhook->is_payment_success ) { ... }
is_payment_failed
Returns 1 if this webhook represents a payment_failed event, 0 otherwise.
if ( $Webhook->is_payment_failed ) { ... }
is_payment_pending
Returns 1 if this webhook represents a payment_pending event, 0 otherwise.
if ( $Webhook->is_payment_pending ) { ... }
resource
Parses the verified webhook payload and returns a Business::Payr::Webhook::Payment object populated with all fields from the payload.
my $Payment = $Webhook->resource;
Throws an exception if the payload has already been cleared or if required fields are missing.
SEE ALSO
Business::Payr::Webhook::Payment
AUTHORS
Lee Johnson - leejo@cpan.org
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. If you would like to contribute documentation, features, bug fixes, or anything else then please raise an issue / pull request:
https://github.com/payprop/business-payr