List view
Getting Started
Getting Started
Authentication Guide
Authentication Guide
Real-Time Bank Transfers Argentina
Real-Time Bank Transfers Argentina
PIX Brazil
PIX Brazil
PagoMovil Venezuela
PagoMovil Venezuela
SPEI Mexico
SPEI Mexico
PSE Colombia
PSE Colombia
Khipu Chile
Khipu Chile
WebPay Chile
WebPay Chile
MACH Chile
MACH Chile
Bank Transfers Chile
Bank Transfers Chile
Real-Time Bank Transfers Paraguay
Real-Time Bank Transfers Paraguay
VISA & MasterCard
VISA & MasterCard
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.
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
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.
"""
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.
"""
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.
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)}" )