Become a Paddle partner
Join the Paddle partner program to read this content. You'll also get access to our partner API and agent tooling. Let us know a few details about your business to get started. Already a partner? Log in to view this page.
Before a seller goes live, test their integration end-to-end in sandbox. Sandbox is a separate environment that uses test cards and processes no real money, so you can exercise every path safely.
You should test with real events wherever you can. Paddle also includes a webhook simulator that you can use to test your handler in isolation.
We recommend running sellers through the testing process when they say something like "I'm ready to go live" or "help me test my integration." If a seller hasn't tested their integration before going live, you should run a testing workflow with them first.
Test checkout with test cards
- Environment
- Sandbox
Ask the seller to open a checkout in sandbox and complete it with a test card. Paddle Checkout renders in a cross-domain iframe, so browser automation tools can't reach inside it, so you must get a seller to do this themselves.
Use Paddle's test cards to complete a checkout:
| Card type | Card number |
|---|---|
| Valid Visa debit card | 4000 0566 5566 5556 |
| Valid card without 3DS | 4242 4242 4242 4242 |
| Valid card with 3DS | 4000 0038 0000 0446 |
| Declined card | 4000 0000 0000 0002 |
| Initial success, subsequent decline | 4000 0027 6000 3184 |
Enter any cardholder name and a valid expiry date in the future.
Check that a subscription is created
Once a checkout is completed, you should check that a subscription is created in the seller's database. If it isn't, review the webhook handler and provisioning workflow, then ask the seller to complete the checkout again.
Automated testing
While you can't fill card details or assert on anything within the checkout itself, you can automate:
- Opening the checkout and asserting it appears.
- The
itemsandcustomDatapassed toPaddle.Checkout.open(). - Paddle.js events like
checkout.completedandcheckout.closed. - Post-checkout state: the subscription your handler created, and UI that updates once the webhook lands.
- Error states when the checkout fails to load.
Test a subscription renewal
- Layer
- Your agent, Your platform
- Authentication
- Seller API key
- Environment
- Sandbox
Using the test subscription the seller created, fast-forward the billing date to trigger a renewal. This sets the billing date to 30 minutes from now, so the renewal will happen shortly rather than at the end of the billing period.
To trigger a renewal, send a PATCH request to the /subscriptions/{subscription_id} endpoint with the new billing date and proration_billing_mode.
If successful, Paddle returns the updated subscription.
{ "next_billed_at": "2026-07-03T11:08:00Z", "proration_billing_mode": "do_not_bill"}{ "data": { "id": "sub_01hv8y5ehszzq0yv20ttx3166y", "status": "active", "customer_id": "ctm_01hv8wt8nffez4p2t6typn4a5j", "address_id": "add_01hv8y4jk511j9g2n9a2mexjbx", "business_id": null, "currency_code": "USD", "created_at": "2026-07-03T10:38:00.761Z", "updated_at": "2026-07-03T10:38:30.000Z", "started_at": "2026-07-03T10:37:59.556997Z", "first_billed_at": "2026-07-03T10:37:59.556997Z", "next_billed_at": "2026-07-03T11:08:00Z", "paused_at": null, "canceled_at": null, "collection_mode": "automatic", "billing_details": null, "current_billing_period": { "starts_at": "2026-07-03T10:37:59.556997Z", "ends_at": "2026-07-03T11:08:00Z" }, "billing_cycle": { "frequency": 1, "interval": "month" }, "scheduled_change": null, "items": [ { "status": "active", "quantity": 10, "recurring": true, "created_at": "2026-07-03T10:38:00.761Z", "updated_at": "2026-07-03T10:38:30.000Z", "previously_billed_at": "2026-07-03T10:37:59.556997Z", "next_billed_at": "2026-07-03T11:08:00Z", "trial_dates": null, "price": { "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", "type": "standard", "description": "Monthly", "name": "Monthly (per seat)", "tax_mode": "account_setting", "billing_cycle": { "frequency": 1, "interval": "month" }, "trial_period": null, "unit_price": { "amount": "3000", "currency_code": "USD" }, "unit_price_overrides": [], "custom_data": null, "status": "active", "quantity": { "minimum": 1, "maximum": 999 }, "import_meta": null, "created_at": "2026-07-01T09:15:00.000Z", "updated_at": "2026-07-01T09:15:00.000Z" }, "product": { "id": "pro_01gsz4t5hdjse780zja8vvr7jg", "name": "AeroEdit Pro", "type": "standard", "tax_category": "standard", "description": "Designed for professional pilots, including all features plus in Basic plus compliance monitoring, route optimization, and third-party integrations.", "image_url": "https://paddle.s3.amazonaws.com/user/165798/bT1XUOJAQhOUxGs83cbk_pro.png", "custom_data": null, "status": "active", "import_meta": null, "created_at": "2026-07-01T09:14:00.000Z", "updated_at": "2026-07-01T09:14:00.000Z" } } ], "custom_data": null, "management_urls": { "update_payment_method": "https://buyer-portal.paddle.com/subscriptions/sub_01hv8y5ehszzq0yv20ttx3166y/update-payment-method", "cancel": "https://buyer-portal.paddle.com/subscriptions/sub_01hv8y5ehszzq0yv20ttx3166y/cancel" }, "discount": null, "import_meta": null, "consent_requirements": [] }, "meta": { "request_id": "e9ce8070-295a-4c8b-9180-7ab58dc31072" }}You can't fast-forward a subscription that's past_due.
Check that a renewal is processed
Renewals process when the new billing date elapses. Check that:
- Paddle created a new transaction for the renewal and it completed successfully.
- A
subscription.updatedwebhook reached the seller's backend, so the cached subscription'sstatus,next_billed_at, andupdated_atchanged in the database. - The customer keeps access.
statusstaysactive, so your access check still passes.
If you used the dunning card (4000 0027 6000 3184), the renewal payment declines instead: subscription.updated fires with status: past_due. The customer keeps access during the retry window while Paddle Retain attempts to recover the payment. Use the customer portal to update payment details and run through the renewal checks.
Test a subscription cancellation
- Layer
- Your agent, Your platform
- Authentication
- Seller API key
- Environment
- Sandbox
Customers can cancel subscriptions using the customer portal, or using links in emails from Paddle. Sellers must build functionality to handle cancellation to avoid giving away free access.
To cancel a subscription, send a POST request to the /subscriptions/{subscription_id}/cancel endpoint, passing effective_from as immediately.
If successful, Paddle returns the updated subscription.
{ "effective_from": "immediately"}{ "data": { "id": "sub_01hv8y5ehszzq0yv20ttx3166y", "status": "canceled", "customer_id": "ctm_01hv8wt8nffez4p2t6typn4a5j", "address_id": "add_01hv8y4jk511j9g2n9a2mexjbx", "business_id": null, "currency_code": "USD", "created_at": "2026-07-03T10:38:00.761Z", "updated_at": "2026-07-03T10:41:00.000Z", "started_at": "2026-07-03T10:37:59.556997Z", "first_billed_at": "2026-07-03T10:37:59.556997Z", "next_billed_at": null, "paused_at": null, "canceled_at": "2026-07-03T10:41:00.000Z", "collection_mode": "automatic", "billing_details": null, "current_billing_period": null, "billing_cycle": { "frequency": 1, "interval": "month" }, "scheduled_change": null, "items": [ { "status": "active", "quantity": 10, "recurring": true, "created_at": "2026-07-03T10:38:00.761Z", "updated_at": "2026-07-03T10:41:00.000Z", "previously_billed_at": "2026-07-03T10:37:59.556997Z", "next_billed_at": null, "trial_dates": null, "price": { "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", "type": "standard", "description": "Monthly", "name": "Monthly (per seat)", "tax_mode": "account_setting", "billing_cycle": { "frequency": 1, "interval": "month" }, "trial_period": null, "unit_price": { "amount": "3000", "currency_code": "USD" }, "unit_price_overrides": [], "custom_data": null, "status": "active", "quantity": { "minimum": 1, "maximum": 999 }, "import_meta": null, "created_at": "2026-07-01T09:15:00.000Z", "updated_at": "2026-07-01T09:15:00.000Z" }, "product": { "id": "pro_01gsz4t5hdjse780zja8vvr7jg", "name": "AeroEdit Pro", "type": "standard", "tax_category": "standard", "description": "Designed for professional pilots, including all features plus in Basic plus compliance monitoring, route optimization, and third-party integrations.", "image_url": "https://paddle.s3.amazonaws.com/user/165798/bT1XUOJAQhOUxGs83cbk_pro.png", "custom_data": null, "status": "active", "import_meta": null, "created_at": "2026-07-01T09:14:00.000Z", "updated_at": "2026-07-01T09:14:00.000Z" } } ], "custom_data": null, "management_urls": { "update_payment_method": "https://buyer-portal.paddle.com/subscriptions/sub_01hv8y5ehszzq0yv20ttx3166y/update-payment-method", "cancel": "https://buyer-portal.paddle.com/subscriptions/sub_01hv8y5ehszzq0yv20ttx3166y/cancel" }, "discount": null, "import_meta": null }, "meta": { "request_id": "f21058d1-281a-4877-bb3b-261a753d08c4" }}Check that a subscription is canceled
Canceling immediately takes effect straight away. Check that:
- Paddle returns the subscription with
status: canceled,canceled_atset, andnext_billed_atandscheduled_changebothnull. - A
subscription.updatedwebhook reaches the seller's backend, so the cached subscription'sstatusbecomescanceledin the database. - The customer loses access.
statusis no longer active, so your access check returnsfalse.
If you cancel at the end of the billing period instead (by omitting effective_from), the subscription stays active with a scheduled_change to cancel. The customer keeps access until scheduled_change.effective_at, then you should revoke their access.