Test mode is a full copy of your business where no real money moves. Payment links, invoices, quotes, checkout, subscriptions, refunds, the API and webhooks all work, on test data that is kept apart from your live data. You can use it before your business is verified, so you can build your integration while verification runs.
Switch test mode on
- In the dashboard, turn on Test mode in the header. Anyone on your team can: the test business has the same people with the same roles.
- An amber bar reading Test mode — no real money moves shows on every page while it is on, and on your test checkout, invoice and billing pages.
- Everything you create is test data: it never appears in live mode, and live data never appears in test mode.
- Turn the switch off (or choose Switch to live in the bar) to go back to your live data.
Test cards
Pay your test checkout with these cards. Use any future expiry date and any three-digit security code. A real card is never charged in test mode.
| Card number | What happens | Webhook event |
|---|---|---|
4242 4242 4242 4242 | The payment succeeds. | payment.succeeded |
4000 0000 0000 0002 | The card is declined; the payment is recorded as failed. | payment.failed |
The sandbox has no test card yet for these: Insufficient funds and other specific decline reasons; 3-D Secure authentication; Disputes. Test how your integration handles them with the event simulator.
Test API keys
With test mode on, Settings → Developers makes test keys, which start with ak_test_. A test key reaches your test data only; a live key (ak_live_) never reaches it. Everything else is the same: the base URL, restricted permissions, idempotency, rate limits, the MCP server and the Node SDK. Every object says which mode it is in with livemode — false in test mode.
export ANYTIME_API_KEY="ak_test_…"
curl "https://anytime-capital.com/api/v1/payments?limit=1" \
-H "Authorization: Bearer $ANYTIME_API_KEY"{
"object": "payment",
"livemode": false,
"id": "pay_7Hq2LmX9cR4tVb",
"status": "paid",
"amountCents": 12500,
"amountRefundedCents": 0,
"netCents": 12088,
"currency": "usd",
"description": "Consulting — October",
"source": {
"type": "payment_link",
"id": "pl_4kTz8QwN2xYb6RcD1mPa"
},
"paymentLinkId": "pl_4kTz8QwN2xYb6RcD1mPa",
"customer": {
"name": "Jordan Lee",
"email": "jordan@example.com",
"country": "US"
},
"card": {
"brand": "visa",
"last4": "4242"
},
"paymentMethod": {
"type": "card",
"label": "Visa •••• 4242"
},
"clientReference": "order_1042",
"metadata": {
"campaign": "fall-launch"
},
"amountDetails": {
"subtotalCents": 12500,
"discountCents": 0,
"shippingCents": 0,
"taxCents": 0,
"customerFeeCents": 0
},
"dispute": null,
"failureMessage": null,
"createdAt": "2026-10-14T16:02:11.000Z",
"paidAt": "2026-10-14T16:02:15.000Z"
}Test webhooks
Webhook endpoints added in test mode receive test events only, and live endpoints never receive them. Each event says livemode: false, on the event and on the object it carries, and is signed with the endpoint's own secret exactly like a live one — so the same handler works for both. See Webhooks.
{
"id": "evt_3f9a1c2b7d4e6f8a0b1c2d3e4f5a6b7c",
"type": "payment.succeeded",
"created": "2026-10-14T16:02:16.000Z",
"livemode": false,
"data": {
"object": "payment",
"livemode": false,
"id": "pay_7Hq2LmX9cR4tVb",
"status": "paid",
"amountCents": 12500,
"amountRefundedCents": 0,
"netCents": 12088,
"currency": "usd",
"description": "Consulting — October",
"source": {
"type": "payment_link",
"id": "pl_4kTz8QwN2xYb6RcD1mPa"
},
"paymentLinkId": "pl_4kTz8QwN2xYb6RcD1mPa",
"customer": {
"name": "Jordan Lee",
"email": "jordan@example.com",
"country": "US"
},
"card": {
"brand": "visa",
"last4": "4242"
},
"paymentMethod": {
"type": "card",
"label": "Visa •••• 4242"
},
"clientReference": "order_1042",
"metadata": {
"campaign": "fall-launch"
},
"amountDetails": {
"subtotalCents": 12500,
"discountCents": 0,
"shippingCents": 0,
"taxCents": 0,
"customerFeeCents": 0
},
"dispute": null,
"failureMessage": null,
"createdAt": "2026-10-14T16:02:11.000Z",
"paidAt": "2026-10-14T16:02:15.000Z"
}
}Test your integration
Some events take days to happen for real: a dispute, a renewal, an invoice paid by bank transfer. The event simulator sends one to your test endpoints now, built from your own test data with the same shape, signature and delivery as the real event. It changes nothing else and moves no money. Use Send test event in the test mode bar, or the API with a test key (a live key gets 403 TEST_MODE_ONLY).
POST /test-helpers/events with type and, optionally, objectId (a pay_…, re_…, inv_… or sub_…; left out, your newest test object that fits). It needs the webhook_endpoints write permission and answers 409 NOTHING_TO_SEND when you have no test object of that kind yet: make a test payment, or load sample data. The full reference is Test helpers API.
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-event-1" \
-H "Content-Type: application/json" \
-d '{"type":"payment.succeeded"}'{
"object": "test_event",
"id": "evt_9b2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e",
"type": "payment.succeeded",
"livemode": false,
"objectId": "pay_7Hq2LmX9cR4tVb",
"deliveries": 1,
"sample": false
}| Event | What data carries |
|---|---|
payment.succeeded | Your newest paid test payment (or objectId, a pay_…). |
payment.failed | Your newest failed test payment. |
refund.created | Your newest test refund (or a re_…). |
dispute.opened | Your newest paid test payment, shown disputed (status: "disputed"), as the real event carries it. |
invoice.paid | Your newest test invoice (or an inv_…), shown paid in full. |
subscription.updated | Your newest test subscription (or a sub_…). |
Payment succeeded (payment.succeeded)
Your newest paid test payment (or objectId, a pay_…).
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-payment-succeeded-1" \
-H "Content-Type: application/json" \
-d '{"type":"payment.succeeded"}'const event = await client.testHelpers.events.create({ type: "payment.succeeded" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forPayment failed (payment.failed)
Your newest failed test payment.
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-payment-failed-1" \
-H "Content-Type: application/json" \
-d '{"type":"payment.failed"}'const event = await client.testHelpers.events.create({ type: "payment.failed" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forRefund created (refund.created)
Your newest test refund (or a re_…).
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-refund-created-1" \
-H "Content-Type: application/json" \
-d '{"type":"refund.created"}'const event = await client.testHelpers.events.create({ type: "refund.created" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forDispute opened (dispute.opened)
Your newest paid test payment, shown disputed (status: "disputed"), as the real event carries it.
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-dispute-opened-1" \
-H "Content-Type: application/json" \
-d '{"type":"dispute.opened"}'const event = await client.testHelpers.events.create({ type: "dispute.opened" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forInvoice paid (invoice.paid)
Your newest test invoice (or an inv_…), shown paid in full.
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-invoice-paid-1" \
-H "Content-Type: application/json" \
-d '{"type":"invoice.paid"}'const event = await client.testHelpers.events.create({ type: "invoice.paid" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forSubscription updated (subscription.updated)
Your newest test subscription (or a sub_…).
curl -X POST https://anytime-capital.com/api/v1/test-helpers/events \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "Idempotency-Key: test-subscription-updated-1" \
-H "Content-Type: application/json" \
-d '{"type":"subscription.updated"}'const event = await client.testHelpers.events.create({ type: "subscription.updated" });
console.log(event.id, event.deliveries); // evt_…, endpoints it was queued forSample data
Owners and admins can choose Load sample data in the test mode bar to fill test mode with three customers, three products, two payment links, an open invoice, a monthly plan with a subscriber, and payments that succeeded, failed and were refunded. Loading it again adds nothing. The links, the invoice and the plan are real test objects you can pay with a test card; the sample payments and the subscriber are records to explore (their ids start pay_sample and mem_sample), so refunding or cancelling one isn't possible.
Reset test data
Reset test data in the test mode bar (owners and admins) deletes every test payment, link, invoice, quote, customer, product, subscription and the rest of your test data. Test API keys, test webhook endpoints, your team and settings stay. Your live data is never touched.
What is different in test mode
- No real money moves, and nothing is paid out.
- Emails never reach customers: receipts, invoices and reminders go to the business's owners and admins (and whoever acted) instead, marked [TEST], saying who they would have gone to.
- Scheduled work runs in live mode only: automatic invoice reminders, trial and card-expiry reminders, scheduled plan changes, usage billing at period end and automatic decisions on held payments. Test your handling of those with the event simulator.
- Test payments never show in Anytime Capital's own reports, and don't count toward pricing offers or referrals.
Shopify, WooCommerce and Zapier
- Shopify: with your store's payment provider in test mode, Shopify's test orders are paid on your Anytime Capital test mode with a test card. See Shopify.
- WooCommerce: turn on Test mode in the plugin settings and paste a test key (
ak_test_…) and a test webhook endpoint's secret. See WooCommerce. - Zapier: connect with a test key to build and try your Zaps on test data, then reconnect with a live key. See Zapier.
Going live
- Finish verification in Settings → Verification (live mode).
- Create a live key and live webhook endpoints in Settings → Developers with test mode off.
- Swap the key and webhook secret in your server's environment. Nothing else in your code changes.
- Check
livemodein your webhook handler if you send test and live events to the same server.