Developer docs v0.1.0

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)
StatusMeaning
incompleteFirst payment not yet successful (declined, or awaiting confirmation). Not retried; becomes incomplete_expired after 23 hours.
incomplete_expiredTerminal after an incomplete subscription ages past 23 hours. A late successful charge opens a durable payment review for external refund/service resolution.
trialingIn a trial; nothing is charged until trial_end, then the first period is charged.
activeBilling is active. Check payment records for confirmation; an elapsed-period resume can be active while its new charge is pending.
past_dueA renewal charge failed. Retries run until next_payment_attempt stops being set.
unpaidRetries exhausted (default action). Can recover if a late payment succeeds.
pausedCollection paused; not billed.
canceledTerminal.

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.