Skip to main content

Official UnusPay SDK for webhook signature verification

Project description

unuspay-sdk

Official UnusPay SDK for webhook signature verification.

Installation

pip install unuspay-sdk

Usage

Flask

from flask import Flask, request, jsonify
from unuspay_sdk import Webhook, WebhookVerificationError
import os

app = Flask(__name__)
webhook = Webhook(secret=os.environ['WEBHOOK_SECRET'])

@app.route('/webhook', methods=['POST'])
def webhook_handler():
    try:
        event = webhook.verify(
            payload=request.data,  # Raw bytes, NOT request.json
            signature=request.headers.get('X-Webhook-Signature'),
            timestamp=request.headers.get('X-Webhook-Timestamp'),
        )

        # Handle the event
        if event['type'] == 'order.completed':
            print(f"Order completed: {event['data']}")
        elif event['type'] == 'payment_link.created':
            print(f"Payment link created: {event['data']}")

        return jsonify({'received': True})

    except WebhookVerificationError as e:
        print(f"Webhook verification failed: {e}")
        return jsonify({'error': str(e)}), 401

FastAPI

from fastapi import FastAPI, Request, HTTPException
from unuspay_sdk import Webhook, WebhookVerificationError
import os

app = FastAPI()
webhook = Webhook(secret=os.environ['WEBHOOK_SECRET'])

@app.post('/webhook')
async def webhook(request: Request):
    try:
        payload = await request.body()  # Raw bytes
        
        event = webhook.verify(
            payload=payload,
            signature=request.headers.get('X-Webhook-Signature'),
            timestamp=request.headers.get('X-Webhook-Timestamp'),
        )

        print(f"Received event: {event['type']}")
        return {'received': True}

    except WebhookVerificationError as e:
        raise HTTPException(status_code=401, detail=str(e))

Django

# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from unuspay_sdk import Webhook, WebhookVerificationError
import os

webhook = Webhook(secret=os.environ['WEBHOOK_SECRET'])

@csrf_exempt
@require_POST
def webhook_handler(request):
    try:
        event = webhook.verify(
            payload=request.body,  # Raw bytes
            signature=request.headers.get('X-Webhook-Signature'),
            timestamp=request.headers.get('X-Webhook-Timestamp'),
        )

        print(f"Received event: {event['type']}")
        return JsonResponse({'received': True})

    except WebhookVerificationError as e:
        return JsonResponse({'error': str(e)}, status=401)

API Reference

Webhook class

Main class for webhook signature verification.

Constructor

Webhook(secret: str, config: Optional[WebhookConfig] = None)

Parameters:

Parameter Type Required Description
secret str Yes Your webhook secret (starts with whsec_)
config WebhookConfig No Optional configuration (see below)

verify method

Verifies a webhook signature and returns the parsed payload.

webhook.verify(payload: Union[str, bytes], signature: str, timestamp: Union[str, int]) -> Any

Parameters:

Parameter Type Required Description
payload str or bytes Yes Raw request body (NOT parsed JSON)
signature str Yes Value of X-Webhook-Signature header
timestamp str or int Yes Value of X-Webhook-Timestamp header

Returns: Parsed event dictionary

Raises: WebhookVerificationError if verification fails

WebhookConfig class

Optional configuration for webhook verification.

WebhookConfig(max_age_seconds: int = 300)

Parameters:

Parameter Type Default Description
max_age_seconds int 300 Max event age in seconds

WebhookVerificationError

Exception raised when verification fails.

Attributes:

  • message: Human-readable error message
  • code: Error code ('INVALID_SIGNATURE' | 'TIMESTAMP_EXPIRED' | 'MISSING_HEADERS')

Important: Raw Body Required

Webhook signature verification requires the raw request body (exact bytes as received). Do NOT use parsed JSON.

Common gotchas:

  • Flask: Use request.data, NOT request.json
  • FastAPI: Use await request.body(), NOT await request.json()
  • Django: Use request.body, NOT json.loads(request.body)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unuspay_sdk-0.1.1.tar.gz (24.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unuspay_sdk-0.1.1-py3-none-any.whl (5.0 kB view details)

Uploaded Python 3

File details

Details for the file unuspay_sdk-0.1.1.tar.gz.

File metadata

  • Download URL: unuspay_sdk-0.1.1.tar.gz
  • Upload date:
  • Size: 24.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for unuspay_sdk-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2e784fcc5eb282434dc9b331014ea3c0f47954f50a6bc755a7de415e1c79e9ba
MD5 19e7f0632e2a1982772e97f72e6fd263
BLAKE2b-256 76b4df0dcd6f8e2c32df31349989f9701d5c66429d9cc1a7362d005f4364cd94

See more details on using hashes here.

File details

Details for the file unuspay_sdk-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: unuspay_sdk-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 5.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for unuspay_sdk-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f88b5a0ecb9a7912cb7144ce19b8349480881e289e056ea1808477ee90c21a16
MD5 980504c146fe724f48a4682cb8099921
BLAKE2b-256 59684fd55a226ee5f7f9a0bb48deca7b50640990c32880834c68856478321a55

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page