The PayPal integration (src/revenue_os/paypal.py) is read-only: it books
payments PayPal has already captured into the RevenueLedger. It cannot move
money. Switching to live only changes which PayPal account is read.
paypal-sync uses the
Transaction Search API, which personal accounts do not have.paypal-sync; not for paypal-verify). Allow a short activation delay.custom_id (or the
invoice custom field) to the exact candidate name – same mapping rule as
sandbox..env:
PAYPAL_CLIENT_ID=<live client id>
PAYPAL_CLIENT_SECRET=<live secret>
PAYPAL_ENV=live
.env automatically – export the vars into the shell
before running the CLI. PowerShell:
$env:PAYPAL_CLIENT_ID = "<live client id>"
$env:PAYPAL_CLIENT_SECRET = "<live secret>"
$env:PAYPAL_ENV = "live"
pip install -e . once, or set
$env:PYTHONPATH = "src" per session..env stays gitignored. Never commit live credentials.python -m revenue_os paypal-sync --dry-run --days 1
Read-only: fetches an OAuth token, lists transactions, books nothing.
would book 0 payment(s) ... 0 skipped -> credentials valid, Transaction
Search enabled. (Confirmed working on 2026-08-29.)PayPal API 401 -> wrong client id/secret, or still sandbox values.PayPal API 403 -> Transaction Search not activated yet.When a real payment arrives, verify it singly first:
python -m revenue_os paypal-verify <candidate> <order-id>
then switch to paypal-sync (without --dry-run) for routine booking.
record_payment books the returned currency
as-is. Transaction Search lags up to ~3h; --days max is 31.launched or earning, or the payment is skipped.