Skip to main content
An 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 before currentPeriodEnd, Yabetoo:
  1. generates the invoice for the upcoming cycle (billingReason: "subscription_cycle", period [currentPeriodEnd, currentPeriodEnd + interval]) and finalizes it — it gets its number;
  2. emails it to the customer, with a payment link to the hosted page;
  3. emits invoice.finalized.
The subscription’s period itself does not move: day D advances it. The customer can settle that invoice from the link, any time before the due date. In that case you receive 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 every active 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.
There is no debit. At each due date the customer receives a request on their phone and has to approve it. A customer who does not answer within the window is a nominal case: that is who the D-3 invoice with its link is for, and why retries exist.

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 a past_due subscription, it is already advanced.
  • The latest paid invoice (GET /v1/subscriptions/{id}/invoices): how far the customer has paid.
  • statistics.nextPaymentDate and statistics.nextPaymentAmount on 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.