Laravel Recurring Billing
Set up recurring billing with Laravel and Wajub using recurring invoices — there is no dedicated plans/subscriptions API.
This recipe previously described a fictional API
There is no merchant-facing plans/subscriptions/coupons REST surface in the Wajub API —
$wajub->plans->create(), $wajub->subscriptions->create(), a customer billing portal
endpoint, and events like subscription.created/invoice.payment_succeeded do not exist.
This page has been rewritten around what's actually available: recurring invoices.
The real building block: recurring Invoice
Wajub's recurring billing primitive is a property of a regular
Invoice: set is_recurring: true and a recurring_frequency
(daily/weekly/monthly/quarterly/yearly) on POST /invoices. There is no separate
plan/subscription resource — you model "plans" yourself in your own database (amount,
currency, frequency), and create a recurring invoice per customer when they subscribe.
1. Model a plan in your own app
// database/migrations/xxxx_create_plans_table.php
Schema::create('plans', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->unsignedInteger('amount'); // major unit, e.g. XAF
$table->string('currency', 3)->default('XAF');
$table->enum('frequency', ['monthly', 'yearly']);
$table->timestamps();
});2. Create the recurring invoice when a customer subscribes
use Illuminate\Support\Facades\Http;
class SubscribeCustomer
{
public function handle(Plan $plan, string $customerName, string $customerEmail): array
{
$response = Http::withHeaders([
'Authorization' => config('services.wajub.secret_key'),
])->post('https://api.wajub.com/invoices', [
'customer_name' => $customerName,
'customer_email' => $customerEmail,
'currency' => $plan->currency,
'invoice_date' => now()->toDateString(),
'is_recurring' => true,
'recurring_frequency' => $plan->frequency === 'yearly' ? 'yearly' : 'monthly',
'items' => [
['name' => $plan->name, 'quantity' => 1, 'unit_price' => $plan->amount],
],
])->throw()->json();
return $response['invoice'];
}
}Then explicitly send it:
Http::withHeaders(['Authorization' => config('services.wajub.secret_key')])
->post("https://api.wajub.com/invoices/{$invoiceId}/send")
->throw();3. Track status via webhooks
There is no subscription.created/invoice.payment_succeeded/invoice.payment_failed
event. Listen for invoice.updated and inspect data.status (sent, viewed, paid,
partial, overdue, cancelled, refunded):
// routes/web.php or a dedicated webhook route
Route::post('/webhooks/wajub', function (Request $request) {
// Verify signature — see /tools/webhooks/signature-verification
$event = $request->json()->all();
if ($event['type'] === 'invoice.updated' && $event['data']['status'] === 'paid') {
// mark this billing cycle as paid in your own database
}
return response()->json(['received' => true]);
});No silent debits on Mobile Money
Mobile Money does not support silent recurring charges — each cycle's invoice sends the customer a payment link they must approve. Build reminder/retry logic around that reality rather than assuming card-style automatic renewal.
4. Issuing the next cycle
Since there's no automatic subscription engine, your app is responsible for creating the
next recurring invoice once the current cycle's due date passes — e.g. a scheduled command
that queries active subscriptions and calls the same SubscribeCustomer-style logic again.
Related pages