intermediate
juicer
payouts
stripe-connect

Juicer Payouts

How Juicer payouts work in Levy Swap — Stripe Connect Express transfers, platform fees, the payout cron, holds and reversals, and the 1099 process

Levy Fleets TeamMay 18, 20266 min read

Juicer Payouts

When a Juicer completes a drop cleanly, the platform queues a payout row. Payouts clear via Stripe Connect Express transfer to the Juicer's bank, typically within 24 to 48 hours of drop completion.

The Payout Row

Every completed session generates exactly one juicer_payouts row with:

  • session_id — the session that triggered the payout
  • juicer_id — recipient
  • amount_cents — net to Juicer
  • platform_fee_cents — Levy's cut (default 15%, configurable per subaccount)
  • stripe_transfer_id — populated when the transfer succeeds
  • statusqueued, paid, on_hold, reversed, or canceled
  • scheduled_for — earliest time the payout can drain
  • created_at — when the bounty completed

How the Platform Fee Is Computed

ComponentCentsExample ($5 base, 1.5x surge)
Bounty payoutgross$7.50
Platform fee15%$1.13
Net to Juicergross - fee$6.37

The platform fee is configurable per subaccount. Lower fees subsidize the marketplace; higher fees take more margin. The default 15% is the post-pilot equilibrium.

A separate subaccount_settings toggle controls whether the platform fee is paid by the Juicer (default — fee comes off the Juicer's payout) or by the operator (fee added on top of the operator's bounty cost). Most operators use the default.

The Payout Cron

The juicer-payouts cron runs every 15 minutes. It:

  1. Reads every juicer_payouts row where status = 'queued' and scheduled_for <= now()
  2. For each row, calls Stripe transfers.create with:
    • amount = amount_cents
    • destination = juicer.stripe_account_id
    • idempotency_key = juicer_payout_<id>
  3. On success, writes status = 'paid' and stripe_transfer_id
  4. On failure (insufficient balance, account not enabled, etc.), the row stays queued and the cron retries next cycle

The scheduled_for field defaults to 24 hours after the session completes — gives the operator a window to review and hold if anything looks off. Operators can set the default lower per subaccount (e.g., 1 hour) once they trust their Juicer roster.

When Payouts Are Held

A payout is created in on_hold state instead of queued when any of the following are true at session completion:

  • The session has fraud flags (fraud_flags JSON is non-empty)
  • The Juicer has lifetime_fraud_score &gt;= 25
  • The operator has auto_hold_payouts = true on their subaccount
  • Manual hold action by the operator

Held payouts don't drain automatically — they wait for an operator decision. From the dashboard:

  • Release → moves on_hold to queued with a fresh scheduled_for
  • Cancel → moves to canceled; never paid
  • Reverse (only for paid rows) → calls Stripe transfers.createReversal and moves to reversed

Reversals can take 5–7 business days to actually pull funds from a Juicer's account; if the Juicer has spent the money, the reversal can fail and Levy carries the loss until the Juicer's next payout offsets it.

What Juicers See

Juicers see their payout history in the Juicer app under Earnings:

  • Lifetime total earned
  • Lifetime payouts paid
  • Last 30 days breakdown
  • Per-session detail with the bounty amount, platform fee, and net
  • Stripe-backed transaction IDs for each paid transfer

If a payout is on hold or reversed, they see "Under review" with the operator's contact info. They never see the operator's internal note or fraud-score detail — just the high-level state.

Operator View

The operator dashboard at Dashboard → Swap → Payouts is the ledger of every payout for every Juicer in the subaccount:

ColumnMeaning
DateWhen the session completed
JuicerName + email
SessionClick for the full claim → drop trail
GrossBounty payout pre-fee
Platform feeLevy's cut
NetWhat the Juicer received
Statequeued / paid / on_hold / reversed / canceled
Stripe transferClick out to Stripe dashboard

The page totals across the visible date range and supports CSV export for bookkeeping.

1099 / Year-End Tax

Stripe Connect Express generates and delivers the 1099-NEC to each Juicer at year-end based on the transfers Stripe processed during the year. The Juicer's legal name and SSN come from their Stripe Identity verification — they must match exactly or the 1099 is invalid.

Levy doesn't issue separate 1099s — Stripe handles the issuance. The operator's accounting needs to reconcile:

  • Bounty cost — total gross paid (from the Payouts CSV export)
  • Platform fee — total Levy received (also on the export)
  • Net to Juicers — what Stripe transferred (matches Stripe's connect ledger)

If Stripe's records and Levy's records ever drift, contact support — the Stripe transfer is the source of truth and the platform row should match.

Refunds and Disputes

Disputed drops (the operator believes the vehicle wasn't actually charged or wasn't actually in zone) follow the hold → review → release/reverse path:

  1. Operator flags the session from the dashboard
  2. Payout moves to on_hold if not yet paid, or stays paid pending review
  3. Operator reviews the photos, GPS, charge duration
  4. If valid drop → release / no action
  5. If invalid → reverse + add a fraud-score hit + optional Juicer ban

There's no Juicer-initiated dispute path today — Juicers contact the operator directly through the support email exposed on the Earnings page. Operator-initiated reversals are final and not appealed through the platform.

Common Issues

  • Payout stuck in queued past scheduled_for — the Stripe Connect account isn't fully enabled. Check the Juicer's stripe_account_payouts_enabled flag and the Stripe Connect dashboard.
  • Transfer failed with "insufficient balance" — Levy's Stripe account doesn't have enough float. Usually transient; the cron retries.
  • Juicer says they didn't get paid but status = 'paid' — confirm the Stripe transfer ID and verify the destination account in Stripe. Sometimes the Juicer's bank takes 1–3 business days even after Stripe marks paid.
  • Reversal failed — Juicer has spent the money. Levy carries the loss; the next payout to that Juicer is reduced by the reversal amount until balanced.