Vatly
Api Reference

Test helpers

Simulate subscription renewals in test mode so you can verify recurring billing flows end to end.

Test helper endpoints

Vatly provides a small set of test helper endpoints for recurring billing scenarios. These endpoints are only available in test mode.

Use a test_ API token for every endpoint on this page. Test helper endpoints are not available with live credentials.

Fast-forward subscription renewal

POST /v1/test-helpers/subscriptions/{subscriptionId}/fast-forward-renewal

Simulate a renewal cycle for an existing subscription. The subscription must be active and have a scheduled next renewal.

This helper is asynchronous, just like a live renewal. The request is validated straight away, but the renewal itself runs from a queue a few seconds later — so the response returns the subscription as it was before the renewal: renewedAt, renewedUntil, and nextRenewalAt have not moved yet. Follow the order.paid and order.payment_failed webhooks for the outcome, exactly as your live integration should.

Useful for:

  • testing renewal billing flows without waiting for the real billing interval
  • verifying subscription lifecycle events and webhook delivery
  • validating dunning or invoice follow-up automation in your sandbox flow
  • forcing the renewal payment to fail so you can exercise your payment-recovery handling

Request body

The request body is optional. Omit it to advance the billing cycle and leave the renewal payment pending (this endpoint's original behaviour).

AttributeTypeDescription
paymentStatusstringOptional. Outcome to force on the renewal payment. One of paid or failed. Omit to leave the renewal payment pending. failed declines the payment and starts a payment recovery for the renewal order (delivering order.payment_failed to your webhook endpoint); paid settles it.
failureReasonstringOptional. Which decline to simulate. Only valid alongside paymentStatus: failed (sending it with paid is rejected). Soft declines (insufficient_funds, temporary_decline, general_failure) keep the payment method and retry on a multi-week timeline; every other value is a hard decline that drives the customer to supply a new payment method on a short timeline. Defaults to general_failure. Allowed values: insufficient_funds, temporary_decline, general_failure, invalid_mandate, mandate_canceled, account_closed, card_expired, card_lost_or_stolen, invalid_card_details, authentication_failed, fraud_suspected.
The renewal payment is simulated locally — Vatly never submits a charge to the provider sandbox. When paymentStatus is provided it is the deterministic outcome; when it is omitted the payment stays pending, and you can settle or decline it later with Simulate an order payment. A requested failed outcome can start payment recovery even before a payment exists, but paid cannot be applied until there is a chargeable payment. If the payment mandate is not active yet, the cycle still advances. Only one unresolved fast-forward per subscription may be in flight at a time — a second request returns 409 while the first is still queued, running, or awaiting recovery.
Because the simulated payment lives only inside Vatly, it cannot receive a provider-originated chargeback or dispute. Use a normal provider-backed test payment when you need to test chargeback webhooks.
curl -X POST https://api.vatly.com/v1/test-helpers/subscriptions/subscription_Lp3mNvBxKw7RjTgYcZaE/fast-forward-renewal \
  -H "Authorization: Bearer test_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentStatus": "failed",
    "failureReason": "card_expired"
  }'

Errors

StatusMeaning
401Missing or invalid API key
403Endpoint not available for this token or resource
404Subscription not found
409A fast-forward for this subscription is still queued, running, or awaiting recovery
422Invalid request body (for example, failureReason sent with paymentStatus: paid)

Simulate an order payment

POST /v1/test-helpers/orders/{orderId}/simulate-payment

Settle or decline the pending payment of a test order that was charged to the customer's saved payment method — for example a subscription renewal, or a subscription update made with invoiceImmediately: true.

Use this when a test-mode payment on a saved payment method is still pending. Test card payments settle as paid right away. Test SEPA Direct Debit payments settle as paid automatically 10 to 15 minutes after they are created, unless you simulate an outcome first — simulate failed within the first 10 minutes to test your payment-recovery handling. Payments created locally by the fast-forward and payment-recovery helpers are never settled automatically; they stay pending until you simulate an outcome here.

Unlike fast-forward renewal, this does not advance the billing cycle — it only resolves a payment that is already awaiting an outcome.

This helper is asynchronous, just like a live payment. The request is validated straight away, but the outcome is applied from a queue a few seconds later, so the returned order is still awaiting payment. Follow the order.paid / order.payment_failed webhooks for the result.

Request body

AttributeTypeDescription
paymentStatusstringRequired. Outcome to force on the order's pending payment. One of paid or failed. paid settles it (delivering order.paid); failed declines it and starts a payment recovery (delivering order.payment_failed).
failureReasonstringOptional. Which decline to simulate. Only valid alongside paymentStatus: failed (sending it with paid is rejected). Soft declines (insufficient_funds, temporary_decline, general_failure) keep the payment method and retry on a multi-week timeline; every other value is a hard decline that drives the customer to supply a new payment method on a short timeline. Defaults to general_failure. Allowed values: insufficient_funds, temporary_decline, general_failure, invalid_mandate, mandate_canceled, account_closed, card_expired, card_lost_or_stolen, invalid_card_details, authentication_failed, fraud_suspected.
A payment that already completed or failed cannot be simulated again. If the payment mandate is not active yet, no payment exists: failed still starts a payment recovery, but paid is rejected. Only one simulation per order can be queued at a time — a second request while one is queued returns 409.
curl -X POST https://api.vatly.com/v1/test-helpers/orders/order_Hn5xWqVfKm8RjTgYbUcP/simulate-payment \
  -H "Authorization: Bearer test_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentStatus": "paid"
  }'

Errors

StatusMeaning
401Missing or invalid API key
403Endpoint not available for this token or resource
404Order not found
409A simulation for this order is already queued
422Invalid request body (for example, failureReason sent with paymentStatus: paid, or paid requested before a chargeable payment exists)
Copyright © 2026