# Retry, Scheduler, Merchant Webhook, and Payout Operations

## Retry safety

- Financial finalization uses Redis locks (`invoice-finalize:{id}`) plus database row locks and ledger idempotency.
- Payout broadcast uses `payout-broadcast:{id}` and a deterministic provider reference (`payout-{public_id}`).
- `BroadcastPayoutJob` has one application attempt. An ambiguous provider timeout moves the payout to `manual_review` and raises `PAYOUT_BROADCAST_AMBIGUOUS`; it never blindly creates another transfer.
- Provider/network reads use bounded exponential backoff with jitter where automatic retries are safe.
- Validation, policy, allowlist, screening, and kill-switch failures are non-retryable.
- Laravel's `failed_jobs` table is the dead-letter store. Critical exhausted paths also write `operations_alerts` records for operations tooling.

## Merchant webhook delivery

Payload bytes are persisted in `webhook_deliveries.raw_payload`. Every attempt is stored in `webhook_delivery_attempts`, including timestamp, signature, exact request body, status, bounded response body, error, and duration.

Retry schedule: immediate, 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours, 24 hours. Any 2xx response is accepted. Live redirects are disabled. DNS is resolved and all target IPs must be public. Connect/read timeouts and response capture limits are configured in `config/gateway.php`.

Dashboard replay endpoint:

`POST /api/v1/webhook-deliveries/{deliveryId}/replay`

## Payout lifecycle

`pending_screening -> pending_approval -> approved -> broadcasting -> confirming -> completed`

Exception states: `rejected`, `failed`, `cancelled`, `manual_review`.

Creation validates merchant 2FA configuration, asset, network address, minimum amount, and available ledger balance. Funds are reserved atomically. Screening enforces an active allowlist record whose cooling period has elapsed. An authorized operator must approve the payout before broadcast.

Operator endpoint:

`POST /api/v1/operator/payouts/{payoutId}/approve`

Configure `GATEWAY_OPERATOR_EMAILS` as a comma-separated allowlist. Replace this bootstrap policy with a dedicated operator identity/RBAC model before production.

## Kill switches

`payout_kill_switches` supports global, network, asset, merchant, and wallet scopes, optionally per environment. Every screening and broadcast path checks active switches.

## Required production integrations

The included TRON adapter is deliberately read-only for transfers. Connect `createTransfer()` and `getTransfer()` to a reviewed custody/provider adapter that supports deterministic idempotency and lookup. Implement actual TOTP verification, sanctions/blockchain analytics screening, operator RBAC, alert delivery (PagerDuty/Slack/email), and provider-specific reconciliation before mainnet.
