Skip to main content
Gumroad’s payout system allows sellers to configure when and how they receive earnings from their sales.

Payout Schedule Options

Sellers can choose from four payout frequencies:
Default payout schedule
  • Payouts sent every Friday
  • Includes sales from 7+ days ago
  • Most popular option for steady income
User::PayoutSchedule::WEEKLY = "weekly"

Payout Timing

Gumroad uses a delay system to protect against chargebacks:
module User::PayoutSchedule
  PAYOUT_STARTING_DATE = Date.new(2012, 12, 21)
  PAYOUT_RECURRENCE_DAYS = 7
  PAYOUT_DELAY_DAYS = 7
end
  • Delay Period: 7 days from sale to payout eligibility
  • Processing Time: 2-5 business days for bank transfer
  • Total Time: ~2 weeks from sale to bank account
The 7-day delay helps protect sellers and Gumroad from fraudulent chargebacks and payment disputes.

Payout Thresholds

Set a minimum balance before payouts are sent:
# User model
attr_json_data_accessor :payout_threshold_cents, 
  default: -> { minimum_payout_threshold_cents }

def minimum_payout_amount_cents
  [payout_threshold_cents, minimum_payout_threshold_cents].max
end

Default Threshold

  • Minimum: $10 USD (1000 cents)
  • Configurable: Sellers can set higher thresholds
  • Currency-specific: Adjusted for local currency

Why Use Thresholds?

  • Reduce bank transfer fees
  • Accumulate larger payouts
  • Simplify accounting
If your balance is below the threshold on payout day, the payout is skipped and funds roll over to the next payout date.

Configuring Payout Settings

Sellers configure payouts at /settings/payments:
# app/controllers/settings/payments_controller.rb
def update
  # Validate threshold
  if params[:payout_threshold_cents].present? && 
     params[:payout_threshold_cents].to_i < current_seller.minimum_payout_threshold_cents
    return redirect_with_error(
      "Your payout threshold must be greater than the minimum payout amount"
    )
  end
  
  # Update payout settings
  current_seller.update(
    params.permit(
      :payouts_paused_by_user,
      :payout_threshold_cents,
      :payout_frequency
    )
  )
end

Validation

# User model
validate :payout_frequency_is_valid

def payout_frequency_is_valid
  unless [WEEKLY, MONTHLY, QUARTERLY, DAILY].include?(payout_frequency)
    errors.add(:payout_frequency, "is not a valid frequency")
  end
end

Balance Management

View your balance at /balance:
# app/controllers/balance_controller.rb
def index
  payouts_presenter = PayoutsPresenter.new(
    seller: current_seller,
    params: params
  )
  
  render inertia: "Payouts/Index",
    props: {
      next_payout_period_data: payouts_presenter.next_payout_period_data,
      processing_payout_periods_data: payouts_presenter.processing_payout_periods_data,
      payouts_status: current_seller.payouts_status,
      payouts_paused_by: current_seller.payouts_paused_by_source,
      past_payout_period_data: payouts_presenter.past_payout_period_data
    }
end

Balance Types

  1. Unpaid Balance: Funds available for payout
    def unpaid_balance_cents
      balances.unpaid.sum(:amount_cents)
    end
    
  2. Instantly Payable Balance: Available for instant payout
    def instantly_payable_unpaid_balance_cents_up_to_date(date)
      # Balances eligible for instant payout
    end
    
  3. Processing Balance: Payouts in transit
    payments.where(state: "in_progress")
    

Upcoming Payouts

View projected payouts:
def upcoming_payouts
  upcoming_payout_date = next_payout_date
  upcoming_payouts = []
  
  while upcoming_payout_date
    payout_amount = payout_amount_for_payout_date(upcoming_payout_date)
    break if payout_amount < minimum_payout_amount_cents
    
    payout_period_end_date = payout_period_end_date_for_payout_date(
      upcoming_payout_date
    )
    payout_balances = unpaid_balances_up_to_date(payout_period_end_date)
    
    upcoming_payout = Payment.new(
      user: self,
      amount_cents: payout_amount,
      payout_period_end_date: payout_period_end_date,
      currency: Currency::USD,
      state: payouts_status,
      created_at: upcoming_payout_date,
      processor: current_payout_processor,
      bank_account: active_bank_account,
      payment_address: paypal_payout_email
    )
    
    upcoming_payouts << upcoming_payout
    upcoming_payout_date = advance_payout_date(upcoming_payout_date)
  end
  
  upcoming_payouts
end
The balance page shows up to 3 upcoming payouts, helping you plan your cash flow.

Payout Processors

Gumroad automatically selects the payout processor:
def current_payout_processor
  if (paypal_payout_email.present? && active_bank_account.blank?) || 
     !native_payouts_supported?
    PayoutProcessorType::PAYPAL
  else
    PayoutProcessorType::STRIPE
  end
end
  • Stripe: Default for bank account payouts
  • PayPal: Fallback for unsupported countries or when only PayPal is connected

Instant Payouts

Eligible sellers can receive daily payouts:

Eligibility

def eligible_for_instant_payouts?
  # Must meet minimum sales threshold
  # Must have good standing (no fraud flags)
  # Must be in supported country
end

def instant_payouts_supported?
  # Must have debit card connected
  active_bank_account&.supports_instant_payouts?
end

Initiating Instant Payout

# app/controllers/instant_payouts_controller.rb
def create
  result = InstantPayoutsService.new(
    current_seller,
    date: Date.parse(params.require(:date))
  ).perform
  
  if result[:success]
    redirect_to balance_path, notice: "Instant payout initiated successfully"
  else
    redirect_to balance_path, alert: result[:error]
  end
end
Instant payouts may have higher fees than standard payouts. Check the fee schedule before enabling daily payouts.

Pausing Payouts

Payouts can be paused by multiple sources:

User-Initiated Pause

# In Settings > Payments
current_seller.update(payouts_paused_by_user: true)

System-Initiated Pause

def payouts_paused_by_source
  return nil unless payouts_paused_internally?
  payouts_paused_by || PAYOUT_PAUSE_SOURCE_GUMROAD
end
Pause sources:
  • PAYOUT_PAUSE_SOURCE_STRIPE: Stripe verification required
  • PAYOUT_PAUSE_SOURCE_GUMROAD: Fraud prevention or policy violation
  • user: Manually paused by seller

Checking Payout Status

def payouts_paused?
  payouts_paused_by_user? || payouts_paused_internally?
end

def payouts_paused_for_reason
  # Returns human-readable reason for pause
end
When payouts are paused, your balance continues to accumulate. Payouts resume automatically once verification is complete.

Payout History API

Access payout history via API:
# app/controllers/api/v2/payouts_controller.rb
GET /api/v2/payouts

# Query parameters:
# - before: YYYY-MM-DD (end date)
# - after: YYYY-MM-DD (start date)
# - page_key: pagination token
# - include_upcoming: true/false
# - include_sales: true/false (requires view_sales scope)
# - include_transactions: true/false

Response Format

{
  "payouts": [
    {
      "id": "payout_abc123",
      "amount_cents": 50000,
      "currency": "USD",
      "status": "paid",
      "payout_date": "2024-03-15",
      "payout_period_end_date": "2024-03-08",
      "processor": "stripe",
      "bank_account_last4": "1234"
    }
  ],
  "next_page_key": "encoded_pagination_token"
}

Failed Payouts

When payouts fail:
  1. Email Notification: Seller receives email with error details
    def send_payout_failure_email
      # Sent when payout fails
    end
    
  2. Balance Restoration: Funds return to unpaid balance
  3. Retry: Automatic retry on next payout date

Common Failure Reasons

  • Invalid bank account details
  • Closed bank account
  • Bank rejected transfer
  • Insufficient permissions (PayPal)
  • Account verification required (Stripe)
After 3 failed payout attempts, payouts may be automatically paused. Update your payment information in Settings > Payments.

Cross-Border Payouts

For international sellers receiving USD payouts:
def supports_stripe_cross_border_payouts?
  # Returns true for countries that support USD payouts
  # but may not support local currency processing
end

def min_cross_border_payout_amount_usd_cents
  # Minimum amount for cross-border USD payouts
end
Cross-border payouts:
  • Sent in USD via Stripe
  • Converted by seller’s bank
  • May have currency conversion fees
  • Higher minimum thresholds may apply

Best Practices

Set Appropriate Thresholds

Balance transfer fees against cash flow needs. Higher thresholds reduce fees but delay access to funds.

Keep Payment Info Updated

Outdated bank account or PayPal information causes payout failures. Verify details regularly.

Monitor Balance Page

Check upcoming payouts and balance regularly. Address any issues before payout day.

Respond to Verification Requests

Complete Stripe verification promptly to avoid payout delays or suspension.

Build docs developers (and LLMs) love