Testing Bank Transfers Locally
PartyBank bank transfers are confirmed by a real PiggyVest Business (PVB) webhook, not by the initiating request — so testing the flow locally means reproducing that webhook, not bypassing it.
How the mock webhook works
- In any non-production environment (
NODE_ENV !== 'production'), a real call toPOST /partybank/event/:eventId/bank-transfer-detailsreturns a successful mock transfer response and creates the transaction asPending, exactly like production up to this point. - The service then schedules a real, one-shot Google Cloud Scheduler job targeting
POST /partybank/cron/transfer-webhook-simulation, with a 10-second delay — this reproduces the async timing of a genuine webhook rather than completing the transfer inline. - When the job fires, the simulation endpoint validates it actually came from Cloud Scheduler (
X-Cloudscheduler-Jobname+User-Agent: Google-Cloud-Schedulerheaders), then runs the transaction through the samePartybankService.completeTransfer()used by the real PVB webhook — same balance decrement, same vendor-amount recalculation if applicable. - The scheduler job deletes itself roughly a minute after running.
There is no fully-offline mock — this requires gcloud authenticated against the project and a SERVICE_URL Cloud Scheduler can actually reach (typically an ngrok tunnel in local dev).
Prerequisites
gcloud auth login
gcloud config set project live-capital
gcloud services enable cloudscheduler.googleapis.com
Required environment variables:
NODE_ENV=development
GOOGLE_CLOUD_PROJECT=live-capital
GOOGLE_CLOUD_LOCATION=europe-west1
SERVICE_URL=https://your-ngrok-url.ngrok.io
Walking through a test transfer
curl -X POST "https://your-ngrok-url.ngrok.io/v1/partybank/event/123/bank-transfer-details" \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"description": "Test payment",
"accountNumber": "1234567890",
"bankCode": "044",
"recipient": "Test Recipient",
"bankName": "Access Bank",
"vendorId": 456
}'
Watch the logs for the sequence: mock transfer succeeds → scheduler job created → (~10s later) job triggers → simulation endpoint runs completeTransfer() → transaction flips to Completed.
Verify directly if needed:
SELECT reference, transactionStatus, transactionCompletedAt FROM transactions WHERE reference = '<ref>';
SELECT vendorId, amountPaid FROM vendors WHERE id = <vendor-id>; -- if vendorId was passed
Manual completion (no scheduler round-trip)
PartybankService exposes manuallyCompleteTransfer(reference, walletReference, providerReference?, context?) and manuallyFailTransfer(reference, walletReference, reason, context?) — thin wrappers around the same completeTransfer() core function the real PVB webhook and the mock-webhook path above both use, so behavior (balance updates, vendor recalculation) is identical; it just skips the network round-trip.
There is no CLI or admin-UI entry point for these today — despite an older internal doc describing a yarn manual-transfer command, no such script exists in the repo. Using these methods currently means calling them directly (a one-off script, or the Node REPL against a running instance), not a documented command. If you need this regularly, wiring an admin/tooling-registry endpoint to it (see Admin & Internal Tooling) would be a natural way to expose it safely.
Troubleshooting
- "Failed to create scheduler job: Permission denied" — re-run
gcloud auth loginand confirm the account hasroles/cloudscheduler.adminorroles/cloudscheduler.jobRunner. - Webhook simulation endpoint returns 401 — the request is missing the
X-Cloudscheduler-Jobname/User-Agent: Google-Cloud-Schedulerheaders; don't call this endpoint directly except to reproduce that exact header shape. - Job runs but transaction stays
Pending— checkgcloud scheduler jobs describe <job-name> --location=europe-west1and confirmSERVICE_URLis actually reachable from Google's infrastructure (a stale/expired ngrok tunnel is the most common cause).
Related code
src/modules/partybank/partybank.controllers.ts—cronTransferWebhookSimulationsrc/modules/partybank/partybank.service.ts—completeTransfer,manuallyCompleteTransfer,manuallyFailTransfer