Retry billing on a subscription whose billing is failing
const url = 'http://localhost:8080/v1/subscriptions/example/retry-billing';const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://localhost:8080/v1/subscriptions/example/retry-billing \ --header 'Authorization: Bearer <token>'Clears the subscription’s billing_failure and bills it now, with
the same attempt the billing run makes. Use it after fixing the
cause of a failure, to skip the wait, or to restart a parked
subscription. An audit log entry records the retry.
Once the failure is cleared, the outcome of the attempt is never an HTTP error. A 200 has three outcomes:
- Billed. No
billing_failure, andstill_dueis false. A subscription that was overdue for several periods is billed for each of them, one invoice per period. - Failed again. The subscription carries a new
billing_failurewithattempts: 1, and the billing run then retries on its own schedule. This includes an attempt that finished without an error but left the subscription due. - Not completed. No
billing_failure, andstill_dueis true. The attempt was cut short by a lost database connection or a deadlock, and nothing was saved. The subscription is still unbilled, and the next billing run attempts it. Calling this endpoint again answers 409, because the failure is already cleared.
The call bills inline. If it times out part-way through a long catch-up, the response is an error, the invoices already created stay, and the next billing run finishes the rest. The failure may already be cleared at that point, so a repeat call can answer 409.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Header Parameters
Section titled “Header Parameters”Makes the call safe to retry. Send a unique value (a UUID works) and
the same value on every retry. For 24 hours, a repeat with the same
key, method, path and body gets the first response again, with an
Idempotent-Replayed: true header, instead of running again. The
error cases are in docs/api-surface.md. The usage routes do not take
it: each usage event carries its own idempotency_key.
Responses
Section titled “Responses”The retry ran. Read the outcome from two fields.
subscription.billing_failure is present when the attempt
failed again. When it is absent, still_due false means the
subscription billed or had nothing left to bill, and
still_due true means the attempt did not complete and the
subscription is still unbilled.
object
object
The subscription’s priced lines. Each item names its plan.
One priced line of a subscription. It pairs a plan with a quantity.
object
The item’s stored metadata. Absent when empty.
object
Plan the item moves to at pending_plan_effective_at. Absent when no change is scheduled.
When the plan was last changed immediately. Absent until the first such change.
When the subscription was canceled. Absent until then.
A scheduled cancel time, if one is set.
True when the subscription cancels at the end of the current period.
When a scheduled cancel takes effect. Absent when no cancel is scheduled.
Present on a subscription while collection is paused. New invoices are still created, but stay drafts and are not charged.
object
When collection resumes. Absent when the pause lasts until it is cleared. On a pause set by dunning, it is when Hardcount recorded the payment of the invoice the pause was set for.
Who paused collection. operator: you, through the API or the
dashboard; the pause lasts until you resume it or until
resumes_at. dunning: a dunning policy’s pause final action.
A dunning pause lifts by itself once the invoice whose dunning
set it is paid, even if another invoice is still owed. Periods
that ended during the pause keep their draft invoices.
Limits that make Hardcount invoice before the period ends. A threshold invoice bills the period’s usage so far, and no base fee. The period keeps its dates, the base fee is billed as it would be with no threshold, and the period’s next invoice bills the rest of the usage.
object
Usage threshold in cents, compared with the period’s usage so far (the base fee is not counted). Absent when not set.
object
Usage quantity threshold, as a decimal string.
End of the current period (exclusive).
The current period as text, with the last day included, in the tenant’s billing time zone.
Day of the month the subscription bills on (1-31). Absent for calendar-monthly subscriptions.
Present on a subscription while the billing run is failing on the
work that subscription has due now (a period close, or a scheduled
mid-period cancel). Absent otherwise: a subscription that bills
cleanly, or whose due work changed, carries no billing_failure.
After each failed attempt the billing run waits before the next one:
15 minutes, 1 hour, 4 hours, 12 hours, then 24 hours three times.
The eighth failure parks the subscription (parked: true, no
next_attempt_at). A parked subscription is not attempted again
until POST /v1/subscriptions/{id}/retry-billing is called.
Never set on a subscription attached to a test clock.
object
Failed attempts on the work that is due now. At least 1.
The attempt at which the subscription parks (8).
Why the latest attempt failed: a sentence an operator can act on, or a generic line carrying the subscription id as the reference to search the server log for. Never raw error text.
When the latest attempt failed.
The billing run does not attempt the subscription before this instant. The attempt happens on the first run at or after it, so on an hourly schedule it can be up to an hour later. Absent when parked.
True when automatic attempts have stopped.
Period-close invoices this call created. The final
invoice of a scheduled cancel and the first invoice
at a trial end are not counted, so 0 does not mean
the retry failed. Read success from
subscription.billing_failure and still_due.
True when, after the attempt, the subscription has
no billing_failure and is still due for billing.
The attempt did not complete and nothing was saved;
the next billing run attempts the subscription.
Example
{ "subscription": { "status": "draft", "billing_time": "calendar", "pause_collection": { "behavior": "keep_as_draft", "set_by": "operator" } }}Subscription not found.
The retry was refused. Code billing_not_failing: the
subscription has no billing_failure, so there is nothing to
retry. Code invalid_state: the subscription is attached to
a test clock; use the clock’s retry advance instead.