When something breaks, figure out what’s failing, check you’re hitting the right environment, and look at the error response. Most issues come down to: wrong credential, sandbox/production mismatch, missing permission, or a webhook handler that isn’t responding correctly.Documentation Index
Fetch the complete documentation index at: https://docs.whop.com/llms.txt
Use this file to discover all available pages before exploring further.
Quick triage
| Symptom | First check | Go deeper |
|---|---|---|
API calls return 4xx or 5xx | Check the status code, response body, endpoint, and environment. | API request errors |
API calls return 401 | Confirm the API key is present on the server and belongs to the same environment as the API base URL. | API authentication |
API calls return 403 | Check that the app, user, or company has the required permission for the resource. | Permissions and scopes |
OAuth redirects back with error | Read error and error_description from the callback URL. | OAuth errors |
Embedded checkout fails or redirects with status=error | Remount checkout and inspect the plan or checkout configuration you passed in. | Checkout errors |
| Webhooks do not arrive or keep retrying | Verify the endpoint is public, returns 2xx quickly, and uses the raw request body for signature verification. | Webhook delivery |
Embedded elements emit error | Attach onError, log the value, and confirm the session token and element options. | Embedded element errors |
API request errors
Whop returns standard HTTP status codes. When a request fails, the response body tells you why. Most errors include a code and a message:error and error_description fields instead. See OAuth errors for those cases.
| Status | Meaning | What to do |
|---|---|---|
400 | The request is malformed or missing a required field. | Check required parameters, enum values, IDs, and nested object shape. |
401 | The request is missing valid authentication. | Confirm the API key or access token is present, valid, and sent from your server. |
403 | The credential is valid but cannot perform the action. | Check app permissions, OAuth scopes, company ownership, and connected-account context. |
404 | The resource or endpoint was not found. | Confirm the route, API version, and Whop tag ID such as biz_, plan_, mem_, or user_. |
409 | The request conflicts with the current resource state. | Fetch the latest resource state and retry only if the action still applies. |
422 | The request is valid JSON but fails validation. | Show the validation message to the user so they can fix their input. |
429 | Too many requests were sent in a short window. | For /api/v1 requests, authenticated API calls are limited to 600 requests per minute per operation and API credential. Back off until the retry window in the error message has passed. |
5xx | Whop could not complete the request. | Retry with backoff for idempotent operations, then contact support if it persists. |
Rate limits
For/api/v1 requests, Whop tracks request volume per API operation and API credential. The default limit is 600 requests per minute.
When the limit is exceeded, the API returns 429 with:
API authentication
Use the credential that matches where the code runs.| Credential | Use it when | Common mistake |
|---|---|---|
| Company API key | Your server acts for your own company. | Putting the key in browser, mobile, or public client code. |
| App API key | Your app server acts for companies that installed your app. | Calling endpoints for a company that has not installed or authorized the app. |
| OAuth access token | A signed-in user grants your app access to their account. | Treating a user-scoped token like a company-wide API key. |
| iframe user token | A Whop app verifies the user inside an iframe request. | Skipping verifyUserToken or forwarding the token to unrelated clients. |
- Confirm the base URL matches the key: use
https://api.whop.com/api/v1for production keys andhttps://sandbox-api.whop.com/api/v1for sandbox keys. - Confirm IDs use Whop tag prefixes like
biz_,user_,mem_,plan_,prod_,app_,pay_, orch_, not internal numeric IDs. - Log the HTTP status, response body, endpoint, and request ID if one is returned.
- Retry only when the error is transient or rate-limited. Do not retry
401,403, or validation errors without changing the request.
Permissions and scopes
403 and insufficient_scope errors usually mean the credential is valid but cannot perform that action.
- For Whop apps, confirm the app requests the required permissions in Permissions, then save the app settings and reinstall or reauthorize when needed.
- For OAuth, request only the scopes your feature needs, then make sure the user completed the OAuth flow after those scopes were added.
- For dashboard-created API keys, confirm the key belongs to the company you are passing as
company_id. - For connected accounts, confirm whether the parent company or child company should own the action before choosing the
company_id.
OAuth errors
OAuth errors return a standard payload or redirect query string witherror and error_description.
| Error | Meaning | Fix |
|---|---|---|
invalid_request | A required parameter is missing or malformed. | Check client_id, redirect_uri, response_type, code_challenge, and code_challenge_method. |
invalid_grant | The authorization code, refresh token, or access token is expired, already used, or revoked. | Restart the OAuth flow or ask the user to sign in again. Authorization codes are single-use. |
invalid_client | Whop does not recognize the app client. | Confirm you are using the correct app and environment. |
invalid_scope | The requested scope is not valid or not recognized. | Check available scopes in your app settings and remove any typos. |
insufficient_scope | The token does not include the scope required by the endpoint. | Add the scope in your app settings and re-run OAuth consent. |
access_denied | The user or company denied the authorization request. | The user chose not to grant access, or the company restricts this app. |
unsupported_response_type | The response_type parameter is not supported. | Use response_type=code for the authorization code flow. |
unsupported_grant_type | The grant_type parameter is not supported. | Use authorization_code or refresh_token. |
rate_limit_exceeded | OAuth authorize, token, or introspection requests hit a short-window limit. | Back off and respect the Retry-After header if present. |
Checkout errors
Embedded checkout and iOS checkout can fail for different reasons, but you debug them the same way: check the plan or checkout configuration, inspect the callback, and confirm fulfillment on your server.Embedded checkout
- If checkout redirects to
returnUrlwithstatus=error, show a retry state and remount checkout. - If you pass
planId, confirm the plan exists, is active, and belongs to the company you expect. - If you pass
sessionId, confirm the checkout configuration was created server-side and the session has not expired. - If external payment methods redirect away from your page, make sure
returnUrlis set and points to a route that can render success and retry states. - Use webhooks for fulfillment. Client-side
onCompleteor redirect status is useful for UI, but your server should rely onpayment.succeeded.
iOS checkout
Handle expected failures separately from unexpected failures:Webhook delivery
Common webhook issues:- No event received: confirm the webhook URL is publicly reachable, uses
https, and is saved on the right company and environment. - Signature verification fails: pass the raw request body to
whopsdk.webhooks.unwrap. Do not parse JSON before verification. - Retries keep happening: return a
2xxresponse quickly after verification, then do long-running work in a background job. - Duplicate fulfillment: webhooks are delivered at least once. Store
webhook-idor another event identifier and make the handler idempotent. - Unexpected order: do not assume events arrive in chronological order. Fetch the current resource state when ordering matters.
Embedded element errors
SDK elements such asVerifyElement and ResetAccountElement emit error when initialization or operation fails.
Always attach an error handler while developing:
- Confirm the session token was created for the company and user you expect.
- Confirm the container exists and is empty before calling
mount. - Listen for
readyso you know whether the element initialized. - If the element enters an unrecoverable state, call
unmount()and create a new element instance. - For payout and verification elements, confirm the user is eligible for that flow in the current environment.
Sandbox and production
Sandbox data and production data are separate.| Environment | Dashboard | API |
|---|---|---|
| Sandbox | https://sandbox.whop.com | https://sandbox-api.whop.com/api/v1 |
| Production | https://whop.com | https://api.whop.com/api/v1 |
- Create new production API keys.
- Remove the SDK
baseURL/base_urlsandbox override. - Recreate sandbox-only products, checkout links, webhooks, and connected-account records in production.
- Confirm webhook URLs point to production infrastructure, not a local tunnel.
What to include when asking for help
Include as much of the following as you can:- The endpoint, SDK method, or element name that failed.
- The environment: sandbox or production.
- The status code, error body, OAuth
error_description, or elementonErrorvalue. - The Whop IDs involved, with secrets removed.
- The webhook event ID or
webhook-idheader for webhook issues. - A short code snippet showing how you create the client, checkout, OAuth URL, webhook handler, or element.
OAuth
Build the OAuth 2.1 + PKCE flow and handle token refresh.
Webhooks
Verify signatures, handle retries, and process events safely.
Permissions
Choose app permissions and explain them to creators.
Test in sandbox
Test API calls and checkout flows without touching production.

