active subscription is billed in advance, at each currentPeriodEnd, for the period
that starts. The mechanism fits in two daily appointments, both at 11:00 Brazzaville time
(UTC+1).
D-3: the invoice is issued and sent
Three days beforecurrentPeriodEnd, Yabetoo:
- generates the invoice for the upcoming cycle (
billingReason: "subscription_cycle", period[currentPeriodEnd, currentPeriodEnd + interval]) and finalizes it — it gets its number; - emails it to the customer, with a payment link to the hosted page;
- emits
invoice.finalized.
invoice.paid right away, and day D requests nothing.
The reminder does not go out for a subscription whose cancellation is scheduled before the end
of the period (
cancelAt ≤ currentPeriodEnd).Day D: the period advances and payment is requested
The daily cron takes everyactive subscription whose currentPeriodEnd has passed, and for
each, in a single transaction:
1
Advance the period
currentPeriodStart ← old currentPeriodEnd, currentPeriodEnd ← + interval. This is done
before requesting payment, and never rolled back on failure — it is what makes the
cycle’s invoice unique.2
Find or create the cycle's invoice
The D-3 one if it exists, a new one otherwise. The customer balance (credits) is
applied:
amountDue = total − appliedBalance. If it is already paid, everything stops
here — nothing is requested.3
Request the payment
A payment intent is created for
amountDue, and a request is pushed to the customer’s
default payment method — read at that moment, not the one from creation. The call waits
for the operator’s answer.4
Success
Invoice
paid, paidAt set. Events: invoice.paid, payment.completed,
subscription.updated (with the new period boundaries).5
Failure, or no default method
Invoice
open, lastPaymentError set. The subscription becomes past_due,
payment.failed and subscription.past_due are emitted, and the retry schedule starts. See
Failed payments.What you receive
invoice.paid and payment.completed may arrive twice for the same successful renewal
(two internal paths emit them). Deduplicate on data.invoiceId / data.orderId.Reading where a subscription stands
currentPeriodEnd: the boundary of what has been invoiced. On apast_duesubscription, it is already advanced.- The latest
paidinvoice (GET /v1/subscriptions/{id}/invoices): how far the customer has paid. statistics.nextPaymentDateandstatistics.nextPaymentAmounton the detail: the next due date and its amount (discount applied, before tax).
The first cycle
It differs by door:
All following cycles are
subscription_cycle and follow the mechanism above.