Kick the payout batch from the provider webhook
Python · Python · beginner · greenfield
Wires the provider's daily payout webhook to the batch runner. The handler pulls the batch date from the payload, awaits the run, and reports the number of transfers created back to the provider. Kept it thin — all the heavy lifting stays in `run_payout_batch`.
Fintech back office. Each transfer created by the batch moves real money to a vendor's bank account.
Requirements
- Add `handle_payout_webhook(payload)`, the body of the `POST /webhooks/payout` endpoint: when the payment provider's daily webhook fires, run the payout batch for `payload["batch_date"]` (an ISO date string, always present).
- `run_payout_batch(batch_date)` (async) snapshots that date's unsent payouts when it starts, then creates one bank transfer per payout; it takes up to 30 seconds and is NOT safe to run twice concurrently for the same date — two overlapping runs snapshot the same unsent payouts and each sends its own transfers.
- The provider retries the webhook every 5 seconds until it gets a 2xx response, so retries WILL arrive while a batch is still running. The batch for a given date must be started at most once per webhook burst: if a run for that date is already in flight, respond immediately with `{"status": "already-running"}` instead of starting another.
- When the run completes, respond `{"status": "completed", "transfers": <count>}` using the result's `transfer_count`.
- The service runs as a single asyncio worker process, so module-level state is a valid place to track in-flight work.
Files touched
- app/webhooks/payout.py
--- app/webhooks/payout.py
+"""Kick the daily payout batch when the provider's webhook fires."""
+from app.payouts.batch import run_payout_batch
+
+
+async def handle_payout_webhook(payload: dict) -> dict:
+ """Body of POST /webhooks/payout."""
+ batch_date = payload["batch_date"]
+ result = await run_payout_batch(batch_date)
+ return {"status": "completed", "transfers": result.transfer_count}
+