How billing works
Payware bills in advance: each charge records the period it covers. Use payment transactions and outcome events to confirm settlement; scheduled period dates alone do not prove payment.
create ──► incomplete ──paid──► active ──renewal due──► charge next period
│ │ │
│ declined │ fails ├─ success → period advances, stays active
▼ ▼ └─ failure → past_due, retried with backoff
(stays incomplete, past_due ──retries exhausted──► unpaid (or canceled)
expires after 23h → incomplete_expired)
| Status | Meaning |
|---|---|
incomplete | First payment not yet successful (declined, or awaiting confirmation). Not retried; becomes incomplete_expired after 23 hours. |
incomplete_expired | Terminal after an incomplete subscription ages past 23 hours. A late successful charge opens a durable payment review for external refund/service resolution. |
trialing | In a trial; nothing is charged until trial_end, then the first period is charged. |
active | Billing is active. Check payment records for confirmation; an elapsed-period resume can be active while its new charge is pending. |
past_due | A renewal charge failed. Retries run until next_payment_attempt stops being set. |
unpaid | Retries exhausted (default action). Can recover if a late payment succeeds. |
paused | Collection paused; not billed. |
canceled | Terminal. |
Retries. After a failed renewal the subscription becomes past_due and next_payment_attempt
is set. Retries wait 60 min, then 300 min, then 1440 min (the last interval repeats).
BILLING_MAX_RETRIES (default 3) is the number of retries after the first attempt; when they
are exhausted the subscription moves to unpaid (or canceled if the server sets
BILLING_EXHAUSTED_ACTION=canceled). A payment.failed event includes retry_at.
Remote outcomes. Requests use NETOPIA's v2 JSON contract and raw API-key Authorization header. The POS is in the body; outbound amounts convert minor units to major units. Provider states 3/5 can succeed only after response-schema and payment binding checks. Explicit failed states fail; unknown/3DS-required states, HTTP errors, and malformed responses stay unresolved. Mock mode retains the synthetic HTTP-like table used by tests.
Ambiguous results. Transport errors/timeouts remain pending and are reconciled through
POST /operation/status after the configured age. Provider errors are not treated as success.
Unknown provider-ID recovery requires a positively matched order and is not proven live.
See wire contract and limitations.
Unresolved submitted attempts are rescheduled with exponential lookup backoff (5 minutes up to 24 hours). Reconciliation drains up to 10 batches per run. Queued intents await submission and are excluded from provider status lookups.
Timing. The scheduler runs every BILLING_CRON_MINUTES (default 60). Billing is batched; lock
contention, network delays, and backlog can delay work beyond one interval.
Cancellation. DELETE /v1/subscriptions/:id cancels immediately (no refund).
?at_period_end=true, or cancel_at_period_end: true on update, keeps the paid period and
sets a fixed cancel_at deadline and cancels without a further charge once due. This also applies
to paused subscriptions; resume checks the deadline before charging.
Proration. Changing items mid-period charges the price difference for the remaining part of
the period (as a separate payment transaction with proration: true). Prorated decreases return
409 proration_credit_unsupported; no refund transaction or credit is created. With
proration_behavior: "none", items change immediately and their new recurring amount is billed
from the next period. See the update example.