plan_, and invoice items take it as plan_id. Use an invoice when you agree a price with a customer before they pay, such as a quote, a service, or a business order. You build a draft until it’s right, then issue it to lock the totals and open it for payment. Sending it does that and emails it in one call.
Invoices on this page need
Api-Version-Date: 2026-10-24 or later on every request. Requests with an earlier version reach the legacy invoice API, which works differently. See Before you start.How an invoice works
A native invoice is a payment. Its ID starts withpay_ and stays the same after the customer pays, so you can also read it with Retrieve Payment. Each invoice also gets the next number in your account’s own sequence, such as #00000042, or #ACME-00000042 when your account has an invoice prefix.
- You create a draft with items, a customer, and billing details. A draft charges nothing and emails no one.
- You issue it, or send it. Issuing calculates final tax and opens the invoice for payment. Sending issues it and emails it, either now or at a time you schedule.
- The customer pays. Whop charges the customer’s saved payment method when you issue the invoice, or the customer pays through Whop’s hosted checkout.
- You fulfill the order from the
payment.succeededwebhook.
release_method: buy_now rather than a waitlist. A one-time variant is billed once, and a recurring variant starts a subscription when the invoice is paid. See Invoice a subscription. Installment plans are refused.
Before you start
Send the API version
/invoices serves two different APIs, and the Api-Version-Date your request resolves to decides which one answers.
Issue, send, cancel a scheduled send, and generate a PDF exist only in the native API, so they reach native invoices whatever version you send. The paths both APIs have, such as
GET /invoices and POST /invoices/{id}/void, follow the version.
Send the header on every request rather than relying on a key’s pin, so changing keys never moves you between the two. API versions explains pins and the changelog.
The native API doesn’t list or retrieve legacy
inv_ invoices, and the legacy API doesn’t return native ones.
Call the API
The examples on this page call the API through a small helper that sends the version header on every request.Idempotency-Key on every POST so a retry never creates a second invoice or repeats an action. Generate Invoice PDF is the exception: each call makes a new file, so it doesn’t replay responses.
Create a draft
Create Invoice saves a draft withPOST /invoices.
201 Created with the draft. Creating a draft charges nothing, sends no email, and sends no webhook. This response shows a subset of the fields:
account_id is the account issuing the invoice, prefixed biz_. An account API key can leave it out to use its own account. Create Invoice lists every request and response field.
A draft uses its number when you create it, so a draft you discard leaves a gap in your sequence. To discard a draft, void it.
Add items
items takes 1 to 50 items. Each item takes either plan_id for an existing variant or plan to find or create one inline, plus an optional quantity.
An inline plan uses the same find-or-create input as Create Payment, for example { "plan": { "product_id": "prod_xxxxxxxxxxxxx", "plan_type": "one_time", "initial_price": 250, "currency": "usd" } }. It needs plan:create, and an inline product also needs the product permission, access_pass:create or access_pass:update.
Create and update refuse items that break these rules:
- Each item is a buy-now variant of your account. A variant appears once, so use
quantityfor more units. quantityis between 1 and 999,999, and above 1 only for a variant that allows multiple quantities. Recurring variants don’t, so a recurring item’s quantity is 1.- A recurring variant must belong to a product.
- Every item uses the same currency.
- In an invoice with several items, every item that has a product must be a regular product (the standard product type), not an app. Recurring items share one billing period and free trial length, and all items need compatible payment, tax, and access settings. Variants with custom fields or a password can’t be combined. Items without a product, such as a custom fee, can sit beside the rest.
label, which is the product’s title, or the variant’s title for a variant with no product. The email, PDF, and checkout show it.
The draft keeps the price each variant had when you saved its items, so a later price change on the variant doesn’t move the invoice. A one-time item is billed at its price, and a recurring item at its renewal price.
Set the customer and billing details
Send
member_id or email_address, and billing_address or mailing_address_id, never both of a pair. A billing address needs a customer. A customer is optional on a draft and required to issue it.
Whop calculates tax when you issue the invoice, using the billing address to place the customer. When tax applies and Whop can’t tell where the customer is, the issue is refused, so add a billing address whenever you collect tax.
Edit a draft
Update Invoice changes a draft withPATCH /invoices/{id}. Send only the fields you’re changing.
itemsreplaces the whole list and reads each variant’s current price. Leave it out to keep the saved items and prices.- Changing
member_iddrops the saved billing address and payment method unless you send new ones. It keepsrecipient_emails, so send a new list too, or the previous customer still gets the invoice email. email_addressandcustomer_namearen’t accepted. Send a differentmember_idto bill someone else.- A draft with a scheduled send accepts only a change to
recipient_emailsuntil you cancel the send. - Once the invoice is issued, the only change you can make is
recipient_emails, sent on its own, and only while the invoice isopenoruncollectible. Any other edit is refused with a400.
Choose how the customer pays
There are two ways to get paid for an issued invoice. Pick one before you issue it, because the saved payment method goes on the draft.
An issued invoice that bills a product gets a
checkout_link even when it has a saved payment method. If the automatic charge fails, the customer can still pay through checkout.
Charge a saved payment method
Put a saved payment method on the draft withpayment_method_id. It has to be one of the customer’s saved methods. Save payment methods shows how a customer saves one, and List payment methods finds the ones a member has.
When you issue or send the invoice and its total is above zero, Whop:
- Runs the same checks Create Payment runs on a saved payment method.
- Reserves stock for the invoiced quantities and prepares the payment’s fees.
- Returns the invoice as
openand charges the method in the background, off session.
payment.succeeded webhook for the invoice’s pay_ ID. A paid invoice completes the membership, and your metadata is on the charge and the membership. Payment rules on invoice payments covers how your payment rules screen the charge.
If the automatic charge is declined
A declined charge leaves the invoiceopen and returns the reserved stock. Retrieve the invoice as a payment and read failure_message for why the latest attempt failed.
When the charge is declined or needs the customer to act, Whop emails the invoice’s pay link to its recipients, so the customer can pay through checkout instead. It’s the one email Whop sends for an invoice you issue without sending it. It needs a checkout_link and at least one entry in recipient_emails, and it doesn’t count toward the send limit.
Issue the invoice
Issue Invoice turns a draft into an open invoice. Whop checks the invoice again, calculates final tax, and setsstatus to open and totals_status to final. When the invoice has a saved payment method and a total above zero, Whop then charges it, as described in Charge a saved payment method.
- Tax becomes final.
tax_amountisnullon a draft and set once you issue it.totalandamount_dueinclude it. - Whop creates the customer’s membership when the invoice bills a product. It stays drafted, with no access, until the invoice is paid, and it’s what lets the invoice carry a
checkout_link. payment.createdfires once for the invoice’spay_ID.- Issuing again is safe. Issuing an invoice that’s already
openruns the same checks again and, if they pass, returns it unchanged: its totals stay, and nothing is charged again. - Issuing doesn’t email the invoice, apart from the pay link after a declined charge. To email the invoice, send it instead, or deliver the checkout link yourself.
Get the checkout link
An issued,open invoice that bills a product carries a checkout_link, a signed value in the form pay_xxxxxxxxxxxxx.<signature>. It opens the invoice on Whop’s hosted checkout at its fixed price.
1
Read the link from the issued invoice
checkout_link is null unless the invoice is open, so drafts and paid, void, or uncollectible invoices have none. It’s also null for an invoice with no product, one billed to a business buyer, one whose membership was canceled, and when your credential lacks payment:charge. A business buyer is a customer that’s another Whop account rather than a person.2
Build the hosted checkout URL
Split the link at its first
.: the invoice’s pay_ ID comes before it, and the token after it.3
Send it to the customer
Send the invoice to have Whop email the link, or put the URL in your own email or invoice page. Only the invoice’s customer can pay through it. Anyone else is refused and asked to sign in as the invoice’s customer. The link stops working once the invoice is paid, voided, or marked uncollectible.
4
Fulfill from the webhook
Listen for
payment.succeeded for the invoice’s pay_ ID, the same as for the automatic charge. Webhooks shows a handler.Send, schedule, and remind
Send Invoice emails an invoice withPOST /invoices/{id}/send. Sending a draft issues it first, the same as Issue Invoice. Sending an open invoice emails it again.
open invoice needs a checkout_link to be sent, and a draft needs to bill a product to a customer who isn’t a business buyer. A draft that doesn’t can still be sent when it has a saved payment method, because it’s charged instead.
Who gets the email
Each send emails every address once, as a separate email, so recipients never see each other’s addresses. The addresses are:- The email on the customer’s Whop account, which the invoice PDF prints under Bill to.
- Each entry in
recipient_emails.
recipient_emails in lowercase and de-duplicates the list, so an address in both gets one email.
An empty recipient_emails means Whop emails nobody, the customer included. Use it to keep Whop from emailing an invoice:
- Send Invoice refuses the invoice, unless it charges a saved payment method instead.
- No pay link goes out after a declined charge.
- No reminders go out. Clearing
recipient_emailson anopeninvoice stops its remaining reminders.
When Whop charges instead of emailing
A draft with apayment_method_id and a total above zero is charged instead of emailed, the same as when you issue it. If the automatic charge is declined covers what happens when the charge fails. Such a draft can be sent with an empty recipient_emails, because nobody needs the email.
Send limit
Each invoice can be emailed three times in 24 hours, including the send that issued it. A fourth send in that window is refused with a429 whose error.code is invoice_send_limit_reached. Reminders, the pay link after a declined charge, and a send that charges instead of emailing don’t count toward the limit.
Schedule a send
To send a draft later instead, passsend_at. The draft stays a draft and shows the time in scheduled_send_at. At that time, Whop sends it as if you had called Send Invoice then.
- Only a draft can be scheduled, and
send_athas to be in the future. Whop checks the recipients and the pay link when you schedule, the same as for a send now. - Send again with a new
send_atto move the time. - Editing is locked until the send happens or you cancel it. An update that changes only
recipient_emailsstill works, but it can’t remove the last recipient from a draft that won’t be charged. - Cancel Scheduled Send with
POST /invoices/{id}/unschedule.scheduled_send_atreturns tonull, and the draft can be edited again. Canceling an invoice with no scheduled send returns it unchanged. - Voiding a scheduled draft stops its scheduled send.
send_at. If it’s refused, for example because a variant was deleted since you scheduled it, the invoice stays a draft, scheduled_send_at returns to null, and the API doesn’t return the reason. Any other failure is retried about every 10 minutes, up to 12 attempts in all. Until an attempt succeeds or Whop stops retrying, scheduled_send_at shows the time of the next attempt rather than null. Read the invoice after send_at to confirm it’s open.
Reminders
When Send Invoice emails an invoice that has adue_at, Whop also schedules reminders 3, 7, 14, 30, and 60 days after due_at, skipping any whose date has already passed. Each reminder goes to the same addresses as the invoice and says how many days the invoice is past due.
Reminders go out only while the invoice is open, so they stop once it’s paid, voided, or marked uncollectible. A reminder that comes due while a payment is in progress waits until the payment finishes. An invoice you issue without sending, or one that’s charged instead of emailed, gets no reminders.
Download a PDF
Generate Invoice PDF builds the invoice as a PDF and returns a short-lived link to it. It needspayment:basic:read and works at any status.
url and expires_at. The link works for 15 minutes, and anyone holding it can download the file. Generate a new one when it expires.
The PDF leads with your business: your account’s name heads the page, and the footer says Whop Inc issues the invoice in your name and on your behalf. It shows the invoice number, its date and due date, and the Bill to details. Each item shows its quantity, unit price, and amount, followed by the subtotal, service fee, tax, and amount due. An invoice with a recurring item also states the renewal amount and how often it renews. A draft’s PDF shows its estimated totals, with tax at zero until you issue it.
Some content depends on your credential’s permissions:
Invoice a subscription
Put a recurring variant on an invoice to start a subscription when the customer pays it. Whop then renews it like any other subscription.- The invoice bills the first period. A recurring item must belong to a product, has a quantity of 1, and is billed at the variant’s renewal price. The variant’s free trial and initial fee don’t apply, so add a setup fee as a one-time item beside it.
- Paying the invoice starts the subscription, whether Whop charges the saved payment method on issue or the customer pays through the
checkout_link. The first period starts at the payment. The checkout opened from the link states the renewal amount, including the invoice’s buyer fee, and how often it renews. - Each renewal charges the payment method that paid the invoice, once per billing period. It bills only the recurring items, with the invoice’s buyer fee, at each variant’s renewal price when you issued the invoice. That can differ from the price saved on the draft if the variant’s price changed after you saved the items. One-time items are billed once.
pay_ ID and payment.* webhooks. Renewals aren’t numbered invoices and don’t appear in List Invoices. To find the subscription, retrieve the invoice as a payment and read its membership_id, which needs member:basic:read.
Statuses and lifecycle
status takes its values from payments, so an invoice can also show a payment state such as pending while a payment is in progress. totals_status tells you whether the money fields are final: estimated while the invoice is a draft, final after you issue it. overdue is true for an open or uncollectible invoice whose due_at has passed.
Void or mark uncollectible
Void Invoice cancels adraft, open, or uncollectible invoice. Voiding an invoice that’s already void returns it unchanged, and a paid invoice can’t be voided.
Mark an invoice uncollectible to record that you don’t expect to collect it. Only an open invoice can be marked, and marking an uncollectible invoice again returns it unchanged. An uncollectible invoice has no checkout_link and gets no reminders.
This example marks an open invoice uncollectible, then voids it:
List and retrieve invoices
List Invoices returns the invoices your credential can read, newest first. An API key sees its own account, and a user token sees every account the user can read payments for. Narrow the list with these query parameters:
Sort with
order (created_at or due_at) and direction (asc or desc). Sorting by due_at puts invoices without a due date last. The response is { data, page_info }. While page_info.has_next_page is true, pass page_info.end_cursor as after to read the next page.
pay_ ID. List Payments leaves drafts out.
To export invoices as a CSV file, call Create Export with resource: "receipt_invoices". It needs payment:basic:read and payment:basic:export. The customer columns appear only when your credential also has member:basic:read or member:email:read.
Webhooks
Native invoices send payment webhooks for theirpay_ ID. The invoice.* events belong to the legacy invoice API, and native invoices don’t send them.
Other
payment.* events, such as payment.failed, can also arrive for the invoice’s pay_ ID as its payment attempts change. Subscribe to them with the webhooks guide.
To fulfill an order, save the invoice’s id with the order when you create the draft. The data of a payment.succeeded event is the payment, so data.id is the invoice’s pay_ ID. After you verify the event, look up the order by that ID. In this handler, orders stands for your own order store:
fulfilled keeps a redelivered event from fulfilling the order twice. Subscription renewals have their own pay_ IDs, so they don’t match an invoice.
Payment rules on invoice payments
Your payment rules run on invoice payments after Whop’s own fraud screening, as they do on any checkout. What they can do depends on whether the customer is present.- The automatic charge on issue is off session. A
blockrule declines it, and anallowrule exempts it from your other rules.reviewandenforce_3dsrules are skipped because the charge is off session. - A payment through the checkout link is on session. All four actions apply, with the eligibility limits in Manage fraud.
customer_email is the email on the customer’s Whop account. The payment’s payment_rule_matches lists the rule that decided it. A skipped rule isn’t listed.
Invoices in the dashboard
The Invoices page lists, creates, and sends native invoices. Legacy invoices are on its Legacy invoices tab, which Send an Invoice covers.Permissions
Every write needs
payment:charge, the same permission as Create Payment, and every read needs payment:basic:read. The invoice:* permissions belong to the legacy invoice API, and native invoices don’t use them. A create or update that sends an inline plan item also needs plan:create.
Some fields need a permission of their own. Without it, the field comes back null, and recipient_emails comes back empty.
If your credential loses one of these read permissions after a
POST, replaying it with the same Idempotency-Key is refused with a 403 whose error.code is invoice_replay_permission_revoked when the stored response shows those fields. Fetch the invoice with GET instead. Add permissions from the Permissions guide.
Errors
Refusals come back as{ error: { type, message, code } }. Every code below is a 400 unless it says otherwise. An unknown plan_id, member_id, mailing_address_id, or payment_method_id is a 404, and a timestamp Whop can’t read is a 400 with invalid_timestamp.
These refusals are a 400 with no error.code, so read error.message for the reason:
- An unknown top-level field.
- A
quantityoutside 1 to 999,999. - An invalid address in
recipient_emails, or more than 50 of them. - A broken several-item rule, such as a billing period mismatch.
Create and update errors
Issue errors
Send and schedule errors
Sending a draft issues it, so a send can also be refused for any reason in Issue errors.Other errors
Voiding a paid invoice is a
400 without a code.
Next steps
Invoices API reference
Every invoice endpoint, parameter, and response field.
Save payment methods
Collect the saved payment method an invoice charges on issue.
Manage fraud
Write the payment rules that screen invoice payments.
Listen to webhooks
Track
payment.created and payment.succeeded for your invoices.
