Verifying Signatures

Need to know

  • Webhook messages are signed using HMAC SHA-256 and sent as a hex digest.
  • Each signature uses a subscription secret which is unique to your client, account and resource type.
  • Your subscription secret is provided to you when you create a new subscription.
  • The Paytron signature is stored in the request header as x-paytron-signature.
  • The signature is generated from the full body of the request sent to you by Paytron as JSON.
  • Make sure to check messageId and sentAt attributes in the body to prevent replay attacks.

Obtaining your client secret

Subscription secrets are generated by Paytron when you first subscribe to a resource type. You'll see it included in the response type of the create subscription endpoint.

Once this secret has been generated, it cannot be retrieved again, so make sure to keep a copy in your system.

If you need to rotate your secret, you can call the create subscription endpoint a second time.

How Paytron requests are signed

Every time Paytron sends a message to your callback URL, we'll include a signature on the request so you know it came from us.

Each request is signed with a secret that is unique to your client, account and resource type combo. I.e. the subscription secret used to sign payment messages is different to the one used to sign bill messages.

The signature is generated using HMAC SHA-256 and the full body of the HTTP request, then stored in the header of the request as x-paytron-signature.

Verifying the signature

To verify the signature of any request sent to you by Paytron, simply take your client secret and generate a HMAC SHA256 hex digest from the body of the request.

TypeScript / Javascript

import {createHmac} from 'crypto'

const verifySignature = (subscriptionSecret:string, body:string, paytronSignature:string):boolean => {
   const generatedSignatue = createHmac('sha256', subscriptionSecret).update(body).digest('hex') 
}

Python

import hmac
import hashlib

def verifySignature(subscriptionSecret:str, body:str, paytronSignature:str) -> bool:
    generatedSignature = hmac.new(bytes(API_SECRET , 'utf-8'), msg = bytes(body , 'utf-8'), digestmod = hashlib.sha256).hexdigest()
    return generatedSignature == paytronSignature