SaaS billing in Morocco: charging subscriptions in dirhams and controlling access to your software
SaaS billing in Morocco: model your plans, send a payment link in dirhams at every due date, and open or cut access to your software with signed webhooks.
SaaS billing in Morocco runs on subscriptions in dirhams: on every due date, ChariPay emails your customer a payment link, which they pay by card on a hosted page with 3-D Secure; until they pay, a reminder goes out every day with the same link. Your software listens to signed webhooks to extend access after every successful payment and to restrict it when a period stays unpaid. This guide maps your plans to parameters, then covers sign-up, cutting access, plan changes, invoices and business customers who would rather pay by bank transfer.
SaaS billing in Morocco: how a subscription works
ChariPay is a Moroccan payment platform, a PSP operated by Chari Money, a payment institution licensed by Bank Al-Maghrib. Its subscriptions and recurring payments module covers the full lifecycle of a software subscription, from the first payment to cancellation.
The model fits in a few rules. On every due date, ChariPay generates a single-use payment link and sends it to your customer's email address; they pay it by card on the hosted payment page, with 3-D Secure, and no card data ever passes through your software. As long as the installment is unpaid, a reminder goes out every day with the same link, and no new period opens. Each subscription has a clear status — not yet started, active, paused, completed, canceled — and due dates are computed on the Africa/Casablanca time zone.
On currency, everything is in Moroccan dirhams (MAD): collections, balances, transfers and payouts, with no conversion. API amounts are in major units (149.90 = MAD 149.90).
What about Stripe? Morocco is not in the official list of countries where Stripe is available, published on stripe.com/global and re-read on October 2, 2026; the page says more countries will follow, without naming it. A business established in Morocco therefore cannot open an account there in its own name. Workarounds and their consequences are covered in Stripe in Morocco.
On cost: test mode is free, with no time limit and no commitment. Activation costs MAD 6,000 incl. VAT, paid once when you go live. The commission is a percentage per successful payment, set, like the security deposit, once your application has been reviewed — we publish no "from" rate.
Modeling your plans: billing interval, start date, end date
A pricing plan translates into a handful of subscription parameters. You first create the client (POST /v1/clients), then attach the subscription to it (POST /v1/subscriptions) with an amount, a description and a billing interval.
| Your plan | Subscription parameter |
|---|---|
| Monthly | frequency: MONTHLY |
| Annual | frequency: YEARLY |
| Weekly or daily (special cases) | frequency: WEEKLY or DAILY |
| Date of the first installment | startDate |
| Fixed-term commitment (12 months, a season) | endDate; without endDate, the subscription runs until canceled |
| Channel used to send installment links | channels: ["EMAIL"] |
| Your subscription ID and attributes | externalId and metadata |
The amount (amount) is the price of each period, in MAD, major units. The description (description, 255 characters at most) should make sense to the customer ("Pro plan — monthly" rather than an internal code), because it appears on every installment link they receive. Put the ID of the customer's workspace in your software (for example tenantId) and the plan name in metadata — a flat object of 4 KB at most, carried on every link and every webhook: that is how your code will know which account to open or close. The externalId, unique per account and per environment, prevents creating the same subscription twice if your server retries a request: creating with an existing externalId returns the existing subscription.
The full calls, field by field, are in the guide to subscriptions through the API, and the documentation for every module is in the developer hub.
Watch your plans run before you build the rest: Start in test mode. Three fields (name, work email, company), an activation link sent by email to choose your password, then the portal, where you create your own test key after re-authenticating. In the sandbox, create a subscription whose start date is today: the first link is created immediately and returned in currentCharge; pay it with the test card (4918 9141 0719 5005, CVV 123, 3-D Secure code 555) and the subscription becomes active. With a daily frequency (DAILY), the next installment arrives the following day: you replay a billing cycle, and the access extension that goes with it, without waiting a month. It is free, with no time limit and no approval to wait for: your business verification (KYB) only gates the move to production.
Sign-up, first payment and free trials
When a customer signs up in your software, your server creates their client record and then the subscription. The subscription stays INCOMPLETE until the first payment: the customer receives the first installment's link by email and pays it on the hosted payment page, with 3-D Secure. If the start date is today, that first link is also returned in currentCharge: you can send the customer to its payUrl right after sign-up, without waiting for them to open the email. Until that payment succeeds, do not unlock paid access.
The customer's email is essential: it is where each installment's link and its reminders are sent. Collect a verified address when the account is created in your software, and prefer the company's billing address over that of a user who might leave.
There is no built-in free trial: a deferred start, with a startDate set at the end of the free period, serves the same purpose; no link is sent before that date. What the customer sees between sign-up and that date is something to check in test mode before you announce it on your pricing page. A simple product rule: during the free period your software grants access; after that, only a successful payment extends it.
Granting and cutting access with webhooks
Your software does not need to poll ChariPay: signed events tell it what to do. Three events are enough to drive access:
| Event | What it means | Action in your software |
|---|---|---|
subscription.payment_succeeded | A period was paid | Extend access to the end of the period, issue the invoice |
subscription.payment_failed | A card payment attempt on the installment link failed; the link stays payable | Notify the customer if needed; the installment is still due |
subscription.canceled | The installment stayed unpaid beyond the 14-day deadline: the subscription is canceled automatically | Cut access at the end of the paid period, or right away under your terms |
subscription.canceled signals the automatic cancellation of a subscription whose installment stayed unpaid. When you cancel yourself — from the portal or through the API — do not wait for an event: the response to POST /v1/subscriptions/{reference}/cancel already carries the CANCELED status; update your system at that point. Once it reaches its end date, the subscription becomes "completed".
To tie a subscription payment event to the right workspace, read your metadata, echoed verbatim; for subscriptions, and only for them, the API contract also documents that your externalId and the date of the period concerned (PeriodDate) are echoed. Also store each subscription's reference, returned at creation: GET /v1/subscriptions/{reference} reads its status at any time, and a regular pass over your subscriptions with GET /v1/subscriptions catches any missed event.
Three technical rules keep access from being opened or closed by mistake. Route on the Chari-Event-Type header, not on a guess about the payload. Deduplicate on Chari-Event-Id, not on Chari-Webhook-Id: the latter identifies the delivery, not the event. And verify the signature (X-CHARI-SIGNATURE, X-CHARI-TIMESTAMP) before doing anything. The logic for linking a payment to your business object is covered in matching a payment to its order.
Unpaid periods: choosing your grace period
When an installment is not paid, reminders are automatic: the customer receives an email with the same link every day; while an installment remains unpaid, no new period opens; the link stays payable for 14 days after the due date, then, without payment, the subscription is canceled automatically.
The decision that is specific to SaaS is what happens to access during that deadline. Three policies make sense:
- 1Access maintained until the deadline ends: the gentlest option, suited to long-standing customers and tools their business depends on.
- 2Restricted access (read-only, export allowed, creation blocked): the customer still sees their data and understands they need to act.
- 3Access cut as soon as the installment is not paid on its due date: best kept for low-commitment plans, at the risk of frustrating a customer who simply missed the email.
Whatever your policy, write it into your terms and show it in your software while an installment is awaiting payment, with a button that leads to the installment link (the payUrl in currentCharge). Your software knows each installment's date: it is the absence of subscription.payment_succeeded for that period that triggers your policy. Details on the deadline, your decisions and message templates are in unpaid subscription installments.
Changing plans: upgrades, downgrades and switching to annual
A subscription does not change plans midway: to move from "Starter" to "Pro", from monthly to annual, or to downgrade, cancel the current subscription and create a new one for the same client. That cancellation is yours: it takes effect with no further installment, and the response to the call already carries the CANCELED status, so do not wait for an event. The new subscription follows the same cycle: a payment link on its first due date, sent to the email on the client record; check in test mode what your customer sees when the new plan starts.
There is no proration and there are no coupons: your software sets the effective date. Two common approaches:
- Change at the end of the paid period: the new subscription starts with a
startDatethe day after the last paid period, and the old one is canceled before its next due date. Nobody pays twice for the same period. - Immediate upgrade: you unlock the higher tier right away and start the new subscription at the next due date; the gap for the current period is a commercial gesture you decide on.
Switching to annual follows the same logic: a new YEARLY subscription. For a temporary break, such as a seasonal customer or an annual closure, use a pause instead: pause, resume and cancel are available from the portal or through the API. A pause applies to an active subscription, and resume restarts a paused one. During the pause, no link is sent; on resume, periods that elapsed during the pause are not billed retroactively.
Your invoices stay in your software
ChariPay collects and tracks payments; it does not produce your invoices. Transaction tracking and customer receipts are included, but the invoice, with your numbering and your mandatory details, is your software's job. The pattern to follow:
- 1On every
subscription.payment_succeeded, your software issues the invoice for the period and sends it to the customer. - 2It records the subscription reference and the paid period on the invoice.
- 3When in doubt, it reads a subscription's installment history with
GET /v1/subscriptions/{reference}/charges.
For monthly reconciliation, the portal's CSV export lists every movement with its reference. As for what an invoice must contain and the tax treatment of your business, only your advisor can give an opinion.
Business customers: bank transfers to your RIB
Some business customers prefer to pay an annual subscription by bank transfer. Your ChariPay account allows it: it is a real payment account, held by Chari Money, a payment institution licensed by Bank Al-Maghrib, opened in your company's name, with a RIB in that name and a PDF certificate to download from the portal or through the API. It receives your collections and incoming transfers, and serves your payment operations.
ChariPay is not a bank: your payment account is held by Chari Money. It complements your bank; it does not replace it.
In that case, do not create a ChariPay subscription: issue the annual invoice from your software, share the RIB and the certificate, and unlock access once the transfer is received in your payment account and matched to the right invoice. Keep the two flows separate in your software, payment-link subscriptions on one side and transfers on the other, so that the automatic cutoff for unpaid subscriptions never hits a customer who pays by transfer.
Frequently asked questions
Can you bill a SaaS subscription in dirhams from Morocco?
Yes. With ChariPay, you create a subscription in dirhams: on every due date, your customer receives a payment link by email and pays it by card on the hosted page, with 3-D Secure; until they pay, a reminder goes out every day with the same link. Everything is in MAD, with no conversion, and you can test the full cycle in test mode before going live.
Can I offer a free trial?
Not as a built-in trial: a deferred start serves the same purpose. You create the subscription with a startDate set at the end of the free period (no link is sent before then), and your software grants access during that time. Check in test mode what your customer sees between sign-up and the start date before you announce the offer on your pricing page, and state clearly when the paid subscription starts.
How do I handle a plan change mid-subscription?
A subscription does not change plans: cancel the current one and create a new one for the same client. There is no proration and there are no coupons, so your software sets the effective date, for example with a startDate the day after the last paid period. Switching to annual follows the same rule, with a new YEARLY subscription, making sure the customer never pays twice for the same period.
Does ChariPay issue invoices to my customers?
No. Transaction tracking and customer receipts are included, but the invoice is produced by your software, with your numbering and your mandatory details. Issue it on every subscription.payment_succeeded and, when needed, read the history with GET /v1/subscriptions/{reference}/charges. Record the subscription reference and the paid period on each invoice. On what an invoice must contain, only your advisor can give an opinion.
How do I cut access for a customer who stops paying?
Listen to the signed webhooks. As long as an installment has not received subscription.payment_succeeded, it is unpaid: apply your grace period, with access maintained, restricted or cut. Meanwhile, the customer receives a reminder every day, and the link stays payable for 14 days after the due date; without payment, the subscription is canceled automatically: when subscription.canceled arrives, or when you re-read the status, close access.
Can I bill in a currency other than the dirham?
No. Everything is in Moroccan dirhams (MAD): collections, balances, transfers and payouts, with no conversion. The currency field in responses is always MAD, and API amounts are in major units (149.90 = MAD 149.90). Show your prices in dirhams on your pricing page accordingly, so customers see exactly what they will pay at each due date.
Can a business customer pay by bank transfer instead of by card?
Yes. Your ChariPay payment account has a RIB in your company's name and receives incoming transfers; the PDF certificate can be downloaded from the portal or through the API. Issue the invoice from your software, share the RIB, and unlock access once the transfer is received. Keep that customer outside the automatic cutoff flow used for subscriptions.
Next step
Open your sandbox (Start in test mode) and create a daily (DAILY) subscription that starts today: pay the first link with the test card, then the next day's, to check that each paid installment extends access in your software. Then wire your grace period to installments left without subscription.payment_succeeded, and the access cutoff to subscription.canceled for the automatic cancellation and to the call's response when you cancel yourself, and go live. The guide to subscriptions through the API gives the calls, and the subscriptions and recurring payments page sums up the offer.
Sources
- Stripe — Global availability — read on October 2, 2026
Written by ChariPay team.