> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://mmg-sdk.wetechnologygroup.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://mmg-sdk.wetechnologygroup.com/_mcp/server.

# Handling Webhooks

When a customer completes a hosted checkout, MMG sends an asynchronous callback to your server with the payment result.

Because SDKs are strictly client-side tools, the SDK does not include a callable function to "receive" this webhook. Instead, your backend must act as a server to listen for the incoming request.

However, the Python SDK **does** provide strictly-typed Pydantic models for the webhook payloads, which integrate seamlessly with modern frameworks like FastAPI.

## FastAPI Implementation

The following example demonstrates how to create a webhook listener using FastAPI and the SDK's generated Pydantic models (`CheckoutCallbackRequest` and `DecryptedCheckoutResponse`).

By using `CheckoutCallbackRequest` as the route's payload type, FastAPI will automatically validate that the incoming MMG request contains the required `token` field.

```python
import os
  from fastapi import FastAPI, HTTPException

  from mmg import MmgCheckoutUtil
  from mmg.types import CheckoutCallbackRequest

  app = FastAPI()

  checkout_util = MmgCheckoutUtil(
      environment="Live",  # or "Sandbox"
      public_key=os.getenv("MMG_PUBLIC_KEY"),
      private_key=os.getenv("MMG_PRIVATE_KEY"),
  )


  @app.post("/mmg-sdk/callback/{hash}")
  async def mmg_checkout_callback(payload: CheckoutCallbackRequest):
      """Receive the asynchronous payment result from MMG."""
      try:
          # Decrypt and parse the token in one call
          result = checkout_util.decrypt_callback_token(payload.token)

          if result.result_code == "0":
              print(f"Success! Merchant TXN: {result.merchant_transaction_id}")
              # Fulfill the order in your database
          else:
              print(f"Payment failed: {result.result_message}")

          # MMG requires a 200 OK to prevent webhook retries
          return {"status": "success"}

      except Exception as e:
          raise HTTPException(status_code=400, detail="Failed to process webhook")

```

## Security Best Practices

1. **Keep your Private Key secure:** Never hardcode your RSA private key in your application code. Always load it securely via environment variables or a secret manager.
2. **Dynamic Webhook URLs:** When you initiate the checkout, you pass a dynamically generated webhook URL to MMG (e.g., `https://api.yourdomain.com/mmg-sdk/callback/{hash}`). Ensure this `{hash}` is difficult to guess and mapped to the specific checkout session in your database to prevent replay attacks.
3. **Idempotency:** Webhooks can sometimes be delivered more than once. Ensure your database logic checks if a `merchantTransactionId` has already been processed before fulfilling an order.