Skip to main content
For a recurring plan, Aikeedo creates a subscription when the order is fulfilled and tracks usage against it. Who charges the customer each period, though, depends on your provider.

What Aikeedo does

When an order for a monthly, yearly or lifetime plan is fulfilled:
  1. A subscription is created from the order, copying the order’s external ID and payment gateway.
  2. The workspace is subscribed to the plan, which grants its credits.
  3. Usage resets are scheduled: the first is 30 days out, or after the trial period.
The value your completePurchase() returned becomes that external ID. Everything later, including cancellation and webhook lookups, finds the subscription by it, so return the identifier you’ll need again:

Usage resets are not charges

Aikeedo never charges a card by itself. The renewal cron resets usage and dispatches Billing\Domain\Events\SubscriptionUsageResetEvent. Money only moves if your provider charges on its own schedule, or your plugin listens to that event and charges.
Usage resets run every 30 days, including for yearly plans, because the credit allowance is monthly. Use SubscriptionEntity::getNextBillingAt() when you need the actual next payment date, which follows the plan’s billing cycle.

Model A: the provider manages the schedule

Most providers do. Create a subscription during purchase(), and let the provider bill on its own:
Then completePurchase() returns the provider’s subscription ID, and your webhook handler reacts to cancellations and failed payments.

Creating provider plans

Providers usually need their own plan object, with a price and an interval. Derive it from the order rather than the Aikeedo plan alone, because tax and coupons change what the customer actually pays. A reliable approach is to look up a plan keyed by a fingerprint, and create it if it’s missing:
Store that fingerprint in the provider plan’s name or metadata, and reuse the plan for every customer with the same combination.
Use getTotalPrice(true) when the provider can’t express “discount for the first N cycles”. It applies the coupon to the recurring price instead, which is the closest equivalent most providers support.

Model B: you charge each period

If the provider only gives you a saved payment method or a mandate, charge when Aikeedo resets usage:
src/Plugin.php
src/Listeners/ChargeRecurringPayment.php
Always filter by gateway key first: the event fires for every subscription in the installation, not just yours.

Trials

OrderEntity::getTrialPeriodDays() carries the plan’s trial length. Providers support trials differently, and all of these appear in practice: When the installation has “trial without payment” enabled and the plan has trial days, Aikeedo cancels the subscription right after creating it, so the customer gets the trial period and nothing renews. Don’t fight that: if the order’s trial days are set and no payment was taken, return a reference that reflects reality.

Cancellation

Aikeedo calls this from the user’s billing page, from the admin panel, when a workspace switches plans, and while handling your own webhook.
Make cancelSubscription() idempotent. It’s called even when the provider was the one that cancelled, so a second cancellation must not throw. Treat “already cancelled” and “not found” as success.
Cancelling in Aikeedo sets the subscription to end at its next renewal date, so the customer keeps what they paid for. A separate cron job ends expired subscriptions and moves the workspace to the fallback plan. Use CancelSubscriptionCommand for a normal cancellation, and EndSubscriptionCommand when service must stop now, such as after a failed renewal or a chargeback.

Testing checklist

A recurring plan creates a subscription whose external ID is the one your provider knows.
A trial starts without charging, and the first charge lands when the trial ends.
Cancelling in Aikeedo cancels at the provider, and cancelling at the provider cancels in Aikeedo.
Cancelling twice doesn’t throw.
A failed renewal ends the subscription instead of leaving free access.
Switching plans cancels the previous subscription exactly once.