Callback

 
Queries on Transactions

Callback Configuration


8. Callback Configuration

Description:
 
This module provides a reference implementation for handling PAYELU payment callbacks.
It demonstrates how to validate, process, and respond to transaction status notifications.
 

Estructure Example:

{ "transaction_id": "0e21500d-fe65-4263-9c5d-dc54698f4401", "api_key": 3254841451, "security_hash": "b6d8a2c5d3e4f98b7a12345b93de87a9fef45b123a4b9c887e9b23a8a9c0e4aa.....", "status": "COMPLETED", "message": "Transacción acreditada exitosamente", "reference": "ORDER-20251017-0001", "updated_at": "2025-10-17T10:45:23Z", "pay_type": "payin" }
Key Features:
  • Secure hash validation
  • Transaction status handling
  • Data validation using Pydantic
  • Error handling and logging
    """
from fastapi import APIRouter, Request, HTTPException, status
from pydantic import BaseModel, Field
from typing import Optional
import hmac
import hashlib
router = APIRouter()
class CallbackData(BaseModel):
"""
Validates the structure of incoming callback data from PayElu.
Fields: transaction_id: Unique identifier for the transaction api_key: Random 10-digit number used for security validation security_hash: Hash generated using merchant credentials and api_key status: Current status of the transaction ["PENDING", "COMPLETED", "ERROR"] message: Status description or additional information reference: Optional merchant reference for the transaction updated_at: ISO timestamp of the last status update pay_type: Transaction type identifier ["payin", "payout"] """ transaction_id: str = Field(..., description="Unique transaction identifier") api_key: int = Field(..., description="10-digit security number") security_hash: str = Field(..., description="Security validation hash") status: str = Field(..., description="Transaction status: PENDING, COMPLETED, ERROR") message: str = Field(..., description="Status description") reference: Optional[str] = Field(None, description="Merchant reference ID") updated_at: Optional[str] = Field(None, description="Status update timestamp") pay_type: Optional[str] = Field(None, description="Transaction type: payin or payout")
def validate_security_hash(auth_api_token: str, auth_point_id: str, unique_key: int) -> str:
"""
Generates and validates the security hash for callback authentication.
Args: auth_api_token: Your merchant API token from PayElu dashboard auth_point_id: Your merchant point ID (UUID format) unique_key: The api_key received in the callback Returns: str: Generated hash for security validation Security Flow: 1. Combine unique_key and auth_point_id 2. Use auth_api_token as secret key 3. Generate SHA256 HMAC hash """ part1 = str(unique_key).encode('utf-8') part2 = str(auth_point_id).encode('utf-8') message = part1 + part2 secret = auth_api_token.encode('utf-8') return hmac.new(secret, message, hashlib.sha256).hexdigest()
@router.post("/callback_merchant")
async def callback_merchant(request: Request):
"""
Processes PayElu payment status notifications.
This endpoint: 1. Validates the incoming callback data 2. Verifies the security hash 3. Processes the transaction status update 4. Returns acknowledgment to PayElu Implementation Steps: 1. Set up your merchant credentials (auth_api_token, auth_point_id) 2. Implement security hash validation 3. Add your business logic for each status: - Update order/transaction records - Trigger relevant internal processes - Send notifications to users - Handle any required business operations Returns: dict: Simple success response (PayElu only requires HTTP 200) Raises: HTTPException 400: Invalid data format HTTPException 500: Internal processing error """ try: # Parse and validate the request body data = await request.json() callback_data = CallbackData(**data) # Log callback data for debugging print(f"Callback Merchant Emulator - Data: {callback_data}") print(f"Callback Merchant Emulator api_key: {callback_data.api_key}") print(f"Callback Merchant Emulator security_hash: {callback_data.security_hash}") print(f"Callback Merchant Emulator Transaction ID: {callback_data.transaction_id}") print(f"Callback Merchant Emulator Status: {callback_data.status}") print(f"Callback Merchant Emulator Message: {callback_data.message}") print(f"Callback Merchant Emulator - Reference: {callback_data.reference}") print(f"Callback Merchant Emulator - Updated At: {callback_data.updated_at}") print(f"Callback Merchant Emulator - Pay Type: {callback_data.pay_type}") # SECURITY IMPLEMENTATION # Replace with your merchant credentials from PayElu dashboard # Recommended: Load from environment variables # AUTH_API_TOKEN = os.getenv("PAYELU_API_TOKEN") # AUTH_POINT_ID = os.getenv("PAYELU_POINT_ID") # Validate security hash # calculated_hash = validate_security_hash( # AUTH_API_TOKEN, # AUTH_POINT_ID, # callback_data.api_key # ) # if not hmac.compare_digest(calculated_hash, callback_data.security_hash): # raise HTTPException(status_code=401, detail="Invalid security hash") # TRANSACTION PROCESSING # Implement your business logic here based on status: # match callback_data.status: # case "COMPLETED": # await update_order_status(callback_data.transaction_id) # await notify_customer(callback_data.reference) # case "ERROR": # await handle_failed_transaction(callback_data) # case "PENDING": # await update_transaction_status(callback_data) # Return simple success response # Note: PayElu only requires HTTP 200 status return { "status": "success" } except ValueError as e: # Handle data validation errors raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invalid data format: {str(e)}" ) except Exception as e: # Handle unexpected errors print(f"Merchant Emulator Error processing callback: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error processing callback: {str(e)}" )