Skip to content

Whop money API research ​

Access date: 2026-09-01 (Asia/Manila).
Evidence policy: Whop documentation and the official SDK/repository are primary. “Documented” does not mean the BloxClips account is approved or that the sandbox supports the operation.

Decision ​

The owner has fixed the funding source: BloxClips pays from its own Whop business balance. Use a Whop Current API ledger transfer as the primary candidate, debiting the BloxClips business biz_… account or its resolved ldgr_… balance and crediting a payment-verified creator user_… destination. The source policy is settled; the exact IDs, spendable balance, and account capability remain validation gates.

  • Officially documented: ledger moves credit between Whop balances; the destination schema accepts a user, business, or ledger-account ID.
  • SDK type-confirmed: installed official @whop/sdk 1.0.14 exposes client.transfers.create, type: "ledger", origin_id, destination_id, currency, idempotence_key, metadata/notes, retrieve/list, processing|succeeded|failed, and transfer-created/completed/failed payload types.
  • Not sandbox-confirmed: this audit did not call Whop.
  • Not account-capability-confirmed: the docs do not prove that the configured BloxClips account is funded, verified, geographically eligible, approved for the route, or able to send to the intended users.

Do not use the Payouts API to credit a creator. Its documented operation sends an account or user's existing Whop balance to a saved payout method belonging to that owner. That is the later withdrawal operation Whop should expose to the creator, not BloxClips' earning release.

Candidate rail comparison ​

CandidateCredited destinationFits creator Whop-balance goal?Required identityKey risks/unknownsSandbox evidenceRecommendation
Payouts APIOwner's saved external payout method (potk_…), funded from that account/user's Whop balanceNoOwner biz_… or user_… and that owner's saved payout methodWould conflate BloxClips credit with creator withdrawal; KYC, method, review, cancellation/reversal lifecycle; capability unknownNone; sandbox guide says payout functionality is unavailableReject as BloxClips creator-credit rail
Ledger TransferRecipient Whop ledger/balance, documented destination user_…, biz_…, or ldgr_…; source is the owner-confirmed BloxClips business balanceYes, if direct user destination is enabledExact BloxClips business/ledger origin plus separately verified creator user_…Account approval/funds/reserves/fees/geography and direct-user capability need confirmation; failed transfers may later succeed; no documented cancel/reverse operationNone; sandbox transfer support is unclearPrimary, conditional
Connected-account Ledger TransferCreator-controlled/connected biz_… Whop account balancePartially; credits a business balance, not necessarily the creator's personal user balanceEnrolled connected biz_…, onboarding/verification, BloxClips originAdditional onboarding and account lifecycle; changes UX and identity modelNoneSingle fallback if Whop disallows direct user_… credit
wallet_send / claim_link Transfer typesUSDT Ethereum wallet / bearer-style claim URLNoWallet/email recipient or link claimantWrong destination and custody model; claim links are not automatic creator creditsNoneReject

Sources: Current API overview, create transfer, create payout, and connected-account payments.

API surface and version pinning ​

Whop distinguishes its Current API from legacy endpoints. Current REST calls use https://api.whop.com/api/v1; versioned reference pages currently appear under /api-reference/beta/. Whop's API stability guide says new work should use Current API even though some legacy resources remain dual-served.

Requests should explicitly send Api-Version-Date: 2026-08-31, the latest listed version on the research date, and the webhook subscription should pin the same api_version_date. The versioning guide says an explicit request header wins; otherwise the key's pin or a default can apply. Relevant recent changes include:

  • 2026-08-21: Payout statuses changed to the eight-state model, money fields became decimal strings, and Payout idempotency became header-only.
  • 2026-08-14: webhook envelope company_id became account_id for subscriptions pinned at or after that date.
  • 2026-08-25-1: legacy withdrawal endpoints were retired for the current pin in favor of Payouts.

Pinning is mandatory because parsing money/status/webhook fields without a pin can silently change meaning. Version upgrades should be reviewed, contract-tested, and released deliberately.

Official SDK evidence ​

Bloxclips-backend/package.json declares @whop/sdk ^1.0.14; the lockfile and installed node_modules/@whop/sdk/package.json resolve 1.0.14. The official repository's package manifest also reported 1.0.14 on the access date: whopsdk-typescript.

The installed generated declarations confirm:

  • BaseClientOptions.apiVersionDate, per-request idempotencyKey, timeoutInSeconds, and maxRetries; the SDK default is two retries.
  • CreateTransfersRequest accepts amount, currency, origin_id, destination_id, body idempotence_key, metadata, notes, and ledger|wallet_send|claim_link.
  • A ledger create response is object: "transfer", has ctt_… ID, origin/destination ledger IDs, fee, failure details, and processing|succeeded|failed status.
  • Its comment explicitly warns that a failed transfer can be retried under the same ID and later become succeeded.
  • Webhook types include transfer.created, transfer.completed, and transfer.failed.

This is compile-time/schema evidence, not runtime capability evidence. For money dispatch, set maxRetries: 0 and let the durable local worker own retry classification; an SDK-internal retry otherwise obscures attempt audit and timeout handling.

Credentials and identities ​

Credential types ​

The quickstart and API overview distinguish:

  • Account API key: server-to-server access to one Whop account. This is the least-complex credential for BloxClips moving its own business funds. It must never reach the browser.
  • App API key: server credential for an installed platform app acting across accounts that granted its requested scopes. Relevant only if the connected-account fallback is required.
  • Account-scoped JWT: short-lived account context accepted by current endpoints; not needed for the primary server worker unless Whop prescribes it.
  • User OAuth token: acts with a user's grant. Do not use a creator token to debit BloxClips; use an explicit user/OAuth connection only to prove recipient identity if that is Whop's supported identity flow.

Identifier semantics ​

PrefixMeaning in current docsPayout-design use
biz_…Whop account/businessOwner-confirmed BloxClips source business; connected-account fallback destination
user_…Whop userPreferred creator destination, subject to capability validation
ldgr_…Ledger accountExplicit balance origin/destination and balance reconciliation
potk_…Saved external payout methodUsed by Payouts; deliberately not stored/handled by BloxClips for the primary rail
ctt_…Transfer ID in current create/retrieve responsesUnique local provider-operation correlation
wdrl_…Payout IDExternal withdrawal lifecycle, not creator credit
msg_…Webhook delivery/event IDDeduplication key

The existing BloxClips WhopIdentity.whopUserId was provisioned for support chat. It is not proof that the user chose that balance for payments. See the separate verification design in 04-target-payout-architecture.md.

Permissions and capability gates ​

Permission names below are included only where an official page states them:

OperationDocumented credential/scope evidenceRemaining gate
Create ledger transferCurrent create page accepts Account API key, account JWT, App key, or user OAuth but does not visibly name an operation scope. The older reference labels payout:transfer_funds.Confirm exact Current API permission and enablement in the BloxClips dashboard/with Whop before code relies on the legacy scope name.
Retrieve/list transfersCurrent retrieve/list endpoints accept the same credential classes; exact inline permission was not exposed on the pages inspected.Confirm whether payout:transfer_funds includes reads or a separate scope is required.
List transfer recipientsCurrent docs describe origin-scoped results; searching members of a business can additionally require member:basic:read.Confirm that direct user_… verification can be done without overbroad member access.
Retrieve ledger balance/accountLegacy reference explicitly requires company:balance:read and payout:account:read.Confirm Current replacement/continued endpoint and scopes before rollout.
Receive transfer webhooksTransfer webhook pages state webhook_receive:transfers.Add the scope and reapprove an App installation if an App key is used.
Read payout destinationPayout-method reference states payout:destination:read.Not needed for the primary rail; do not request it merely because Payouts exists.
Top up balanceTop-up create reference states payment:charge.Do not grant to the payout worker. Funding/top-up is a separate finance operation.

The provider can also enforce non-scope capabilities: payments approval/KYC, account ownership, connected-account enrollment, balances, currency/rail availability, geography, risk/velocity controls, and reserves. A successful authentication or rendered API page proves none of these.

Transfers API details ​

Types and destination semantics ​

The create-transfer reference defines:

  • ledger: credit between two Whop balances. Currency is required. Origin and destination can use supported account/user/ledger IDs.
  • wallet_send: on-chain USDT from the origin account's Ethereum wallet. It is not an internal USD balance credit.
  • claim_link: funds a shareable link, pending until claimed/canceled/expired. It is not tied safely enough to the authenticated BloxClips creator.

For BloxClips, request only type: "ledger", currency: "usd", the immutable verified identifier for BloxClips' Whop business balance, the verified user_… destination, an amount in exact transfer precision, and correlation metadata. Never debit a creator/user balance to fund these credits.

Status, failure, cancellation, and reversal ​

Transfer status is processing, succeeded, or failed. processing can represent an on-chain leg for a stablecoin-rails account. The response includes failed_at, failure_code, and failure_reason. The docs/SDK warn that a failed transfer can later be retried under the same transfer ID and succeed; local FAILED therefore cannot be treated as a permanent no-money terminal without retrieval and policy.

Current docs expose create, retrieve, list, list recipients, and created/completed/failed webhooks. No transfer cancellation or reversal endpoint was found. BloxClips must not invent one; corrections after a successful credit require a local recovery policy and Whop confirmation. This differs from the Payouts resource, which documents cancellation while eligible and a provider-driven reversed state.

Idempotency ​

Use both mechanisms currently documented for Transfers:

  1. Idempotency-Key request header: every authenticated Current API POST accepts it. A successful response is cached for 24 hours; same key/body replays, changed body returns 400, in-flight duplicate returns 409, and a use after 24 hours is a fresh operation. Replays include Idempotent-Replayed: true.
  2. Transfer body idempotence_key: documented for ledger and wallet sends; retrying the same operation returns/attaches to the original transfer.

Set both to the same stable local provider-operation UUID unless Whop directs otherwise in capability validation. Persist the exact canonical request hash. Never generate a new key merely because 24 hours elapsed. The local unique operation and provider retrieval/list result—not Whop's 24-hour header cache alone—must prevent duplicates. See the idempotency guide.

Correlation data ​

Ledger metadata allows up to 50 keys, key names up to 100 characters, and string values up to 500 characters. Store only opaque non-secret values such as schema version, payout item UUID, provider-operation UUID, environment, and currency. Do not include email, tax data, handles, raw provider responses, or lists of submission URLs. notes is suitable for a short non-sensitive BloxClips payout label, not the accounting source of truth.

Reconciliation ​

The provider API can retrieve by transfer ID and list/filter transfers by origin, destination, and status. Persist ctt_… as soon as observed. Normal reconciliation should retrieve known IDs; uncertain create calls without a stored ID should query the constrained origin/destination/time window and match the unique metadata/body idempotence key before considering any replay. Never match on amount alone.

The documented failed-webhook example appeared internally inconsistent during research: its event type was failed while a nested example status could render as succeeded. Treat event type as a trigger, persist the payload, and retrieve the transfer before final state change. This is a documentation/schema-example inconsistency, not evidence of live provider behavior.

Payouts API details and rejection rationale ​

The create-payout reference says it sends money from an account or user balance to a saved payout method for that owner. Current requests include owner account/user, amount/currency, and payout_method_id: potk_…; response IDs use wdrl_….

Pinned at or after 2026-08-21, statuses are requested, in_review, processing, completed, reversed, canceled, failed, and denied, with a more detailed non-versioned status_detail. Amounts/fees are decimal strings and idempotency is header-only. Payout cancellation is allowed only under the endpoint's provider conditions; reversal is provider-side return behavior, not a general BloxClips undo.

This rail would require BloxClips to possess or select the creator's external method and act in the creator's withdrawal context. That violates the locked product boundary and increases KYC/method/security responsibility. Creators should use Whop's own payout setup and withdrawal flow after BloxClips credits their Whop balance.

Balances, funding, fees, reserves, and compliance ​

The Current API Retrieve Account reference accepts the reserved ID me for the account associated with an Account API key. Its account object exposes currency balances broken into available, in_transit, pending, and reserve, plus a capabilities.transfer state. Installed SDK 1.0.14 type-confirms the convenience method client.accounts.me().

The older ledger-account reference additionally exposes the backing ledger ID, balance/pending/reserve, transfer fee, payments-approval status, and payout-account details, and accepts a biz_…, user_…, or ldgr_… identifier. These fields must determine how much of the owner-confirmed BloxClips business balance is actually spendable. “Transfer capability active” and positive available balance are both necessary preflight evidence; neither alone proves that a particular creator destination is supported.

The top-up reference describes adding business funds separately from revenue; its permissions must not be granted to the automatic payout worker.

The connected-account guide requires sufficient origin balance and relevant account onboarding/verification. It is explicit about business-to-business platform transfers, which is stronger evidence for the fallback than for direct user credits. The generic Transfer schema's user_… destination is documented, but production approval for that exact BloxClips pattern remains an open provider question.

Whop's reserve guidance documents that risk controls can hold funds, including high reserves under fraud conditions. Accordingly:

  • “ledger balance” is not synonymous with immediately spendable balance;
  • BloxClips must preflight available funds but cannot rely on a preflight to reserve provider funds;
  • provider fees must be recorded separately from creator entitlement and must not silently reduce the promised creator credit;
  • finance must maintain a funding buffer and alert on available-funds shortfall;
  • KYC, compliance review, region/currency, reserve, or account monitoring can block otherwise valid local payouts.

Exact fee schedule, settlement delay, velocity limits, geographic support, and required funding buffer are unconfirmed for BloxClips and require account-specific evidence.

Webhooks ​

The webhook guide uses Standard Webhooks conventions:

  • Verify the unmodified raw body with webhook-id, webhook-timestamp, and webhook-signature using the ws_… endpoint secret. SDK unwrapWebhook is preferred.
  • Reject timestamps outside the five-minute tolerance to prevent replay.
  • Return a 2xx within five seconds, after only signature validation and durable inbox insertion; process asynchronously.
  • Delivery is at least once. Deduplicate on webhook/event msg_… ID with a unique database constraint.
  • Whop retries 12 times over approximately 71 hours; ordering is not guaranteed. A newer event can arrive first.
  • If ordering matters, retrieve current API state. Endpoint failures can lead to disabling, and events missed while disabled are not automatically replayed.
  • Delivery records are available for a limited window (documented as 30 days), so API reconciliation is mandatory.

Subscribe to transfer.created, transfer.completed, and transfer.failed with webhook_receive:transfers and the same API date as outbound requests. Persist the envelope's account_id, event ID/type/version/date, object ID, payload hash/raw encrypted or access-controlled payload, receipt time, and processing result. Reject events for an unexpected origin/account or unknown environment.

Timeouts, conflicts, retries, and rate limits ​

Whop's troubleshooting guide documents a general limit of 600 requests per minute per operation/credential, 429 backoff, 5xx retry guidance for idempotent operations, and 409 handling by obtaining/rechecking current state where applicable.

Money-worker policy:

  • 2xx with transfer object: persist ID and provider state.
  • 400 validation/body mismatch: permanent for that request; operator must correct local configuration/identity and create a formally new operation only after proving no transfer.
  • 401/403: needs review; disable dispatch and alert on credential/permission/capability failure.
  • 404 on retrieve: do not infer no transfer immediately after a create timeout; continue constrained reconciliation through the uncertainty window.
  • 409: treat as an in-flight/uncertain operation; poll/retrieve and replay the same idempotency tuple only according to the documented mechanism.
  • 429: retry with jitter/backoff and same operation/key/body.
  • 5xx/network timeout: state becomes UNKNOWN; reconcile first. A timeout is not evidence that money did not move.

Sandbox ​

The official sandbox guide documents separate dashboard/API hosts and a client baseUrl pointing at https://sandbox-api.whop.com/api/v1. API keys, webhook endpoints, and sandbox data are isolated. It also explicitly lists payout functionality as unavailable. The text does not clearly say whether this limitation covers only external Payouts or also ledger Transfers.

Therefore the sandbox can be described as configured like the API, but transfer, user-recipient, webhook, idempotency, balance, and failure behavior are all unvalidated for this project. Production behavior that sandbox cannot prove includes real account underwriting, compliance/geography, real settlement/fees/reserves, velocity limits, and creator withdrawal eligibility.

Exact setup/test gates are in 05-sandbox-validation.md.

Provider questions to send to Whop ​

  1. Which biz_… and backing ldgr_… identify BloxClips' Whop business balance, and can that balance send USD ledger transfers directly to creator user_… balances through Current API?
  2. Is payout:transfer_funds the exact current scope, and what scopes are needed for create, retrieve/list, recipient verification, balance, and transfer webhooks?
  3. What approval/KYC, country, currency, minimum/maximum, velocity, connected-account, balance, reserve, and fee requirements apply?
  4. Does sandbox implement ledger Transfers despite the “payout functionality” limitation? How are sandbox balance, recipients, failures, webhooks, and idempotency seeded/tested?
  5. How long is body idempotence_key retained for ledger transfers, and is using the same UUID in both header and body the recommended pattern?
  6. What is the authoritative behavior when a transfer reports failed and later succeeds under the same ID? What retry action triggers that transition?
  7. Is there any transfer cancel/reversal/recovery capability not present in the current public reference?

Source register ​

All accessed 2026-09-01: