pex

Approving payouts

Your partners drive conversions. The conversions sit as pending until you approve them. This is your regular review cadence — usually weekly.

Where to find the queue

  • Dashboard: /dashboard/partners/payouts/queue
  • SDK: apex.listPendingPayouts()
  • MCP: list_pending_payouts

What the queue looks like

Conversions are grouped into aging buckets:

BucketAgeWhy it matters
0-30 daysRecentNormal cadence — approve, reject, or let sit
30-60 daysStaleSomething's slowing you down — resolve
60+ daysOverduePartners are waiting a long time — partner trust at risk

For each conversion: partner id, commission amount, event type, date of purchase, any risk signals.

Reviewing + approving

Dashboard

  1. Open the queue
  2. Select the conversions you want to approve (checkboxes)
  3. Click Approve selected — see per-row outcomes (approved / skipped / failed)

SDK — batch approve the 0-30 day bucket

const queue = await apex.listPendingPayouts();
const fresh = queue.buckets["0_30"];
const result = await apex.approvePayouts(fresh.map(c => c.id));
console.log(
  `Approved ${result.approved.length}, skipped ${result.skipped.length}`,
);

What approval does

For each approved conversion:

  1. Status flips pending → approved
  2. A HoldbackEntry is created, splitting the commission into available + held per the partner's tier (25% held for NEW, 15% for TRUSTED, 5% for VERIFIED)
  3. Fee is snapshotted at current rates (25 bps + $0.50 default) — admin edits after this don't change what you owe
  4. approvedAt is stamped

What approval does NOT do

It does not fire the Stripe transfer. The transfer happens later per your autoPayoutPolicy cycle. Reasons:

  • Partners on NEW tier have a 90-day first-payout hold
  • Batching per (partner, cycle) minimizes Stripe fees
  • The holdback window for the held portion has to elapse before full transfer

Rejecting

When a conversion looks wrong (duplicate, suspected fraud, out-of-spec), reject it:

await apex.rejectPayouts([conversionId], "Duplicate purchase — customer service issue");

Rejection:

  • Flips the conversion to reversed
  • Opens a low-severity audit case so patterns surface if one partner gets repeatedly rejected
  • Does NOT count against the partner's trust score directly

If you're rejecting for clear fraud, open a case via /admin/fraud-ops instead — that path triggers the trust-tier regression logic.

Setting your payout cadence

Your merchant-level autoPayoutPolicy determines when transfers fire. Pick per-program via SDK:

await apex.updateProgram(programId, {
  autoPayoutPolicy: "auto_under_cap",
  autoPayoutCapUsd: 500,
});

Three options:

  • manual — every payout needs your explicit click (default)
  • auto — daily, all approved/released commissions transfer automatically
  • auto_under_cap — weekly, auto for partners under autoPayoutCapUsd, queue the rest

Handling shortfalls

If your Stripe balance is short when the scheduled transfer fires, Apex retries in 24 hours. After two failures (~48h), you get an email. See Facilitated payouts → Insufficient balance for the full escalation ladder.

You'll never get an automated "fraud" notification for a shortfall. If you legitimately ran short, Apex treats it as cash flow. Only a human at Apex can reclassify it as fraud after manual review.

Partner-side visibility

By default, partners see "processing" messaging for the first 72 hours of a delay. After that, verified / trusted partners see the reason ("merchant is topping up"), but NEW-tier partners still see masked messaging. The word "fraud" never appears on partner-facing copy.

This is intentional — cash flow issues aren't partner issues.