Payload Signature

For your security, OpenPay signs every webhook request sent to your endpoints. The signature is included in the request's signature-digest header, and it follows the format

t=TIMESTAMP,SIGNATURE_VERSION=SIGNATURE[,SIGNATURE_VERSION=SIGNATURE_2,SIGNATURE_VERSION=SIGNATURE_3,...]

  • TIMESTAMP is an integer representing the POSIX timestamp (seconds since epoch) of the event creation.

  • SIGNATURE_VERSION is v1 right now, but this could change in the future.

  • SIGNATURE is an HMAC SHA256 digest of the string

    TIMESTAMP.DATA

    • DATA is the value of the data key in the payload.

  • There is one signature for every available secret, but you should only need to verify at least one.

Getting the secretCopied!

The signatures are generated using automatically-generated secret keys. You can obtain the secret used to sign payloads for your webhook from the Dashboard.

  1. On the Developers page (where you created your webhook), click on the webhook that you want to get the secret for.

  2. On the webhook’s details page, click the three dots to the right of the webhook name. Select Show Secret from the menu that appears.

  3. You can now copy the secret to clipboard.

If you need to get the secret programmatically (using something like cURL), do the following:

  1. Obtain an OpenPay API token with the ADMIN role. (Webhook secrets can only be accessed using tokens of this role.)

  2. Access the webhook secret from the API:

curl -X GET \
  -H 'Authorization: Bearer SECRET_KEY' \
  https://connto.getopenpay.com/webhook-endpoints/webhook_endpoint_XXXXXXXXXXX/reveal_secret

# JSON response:
# {
#   "id": "webhook_endpoint_XXXXXXXXXXX",
#   // ...
#   "secret": "whsec_XXXXXXXXXXXXXXXX"
# }

Verifying a signatureCopied!

To verify a signature, you will need to generate your own signature using the same data as above and compare the two digests.

from getopenpay.client import ApiKeys, OpenPayClient
from getopenpay.utils.webhook_utils import InvalidSignatureError

client = OpenPayClient(ApiKeys(...))
                       
secret_key = 'whsec_XXXXXXXXXXXXXXXX'
event_data = "{\"id\": \"event_dev_abcdefg12345678\", \"object\": \"event\", ...}"
signature_digest = request.headers.get('signature-digest', None)

try:
  client.webhook_utils.validate_payload(
    event_data=event_data,
    signature_digest=signature_digest,
    secret=secret_key
  )
except InvalidSignatureError:  # or ValueError
  # ...

import hmac
from hashlib import sha256

secret_key = 'whsec_XXXXXXXXXXXXXXXX'

content = f'{TIMESTAMP}.{DATA}'
signature = hmac.new(
    secret_key.encode('utf-8'),
    content.encode('utf-8'),
    digestmod=sha256
).hexdigest()

expected_signature = request.headers.get('signature-digest')
is_valid = hmac.compare_digest(signature, expected_signature)