Skip to main content
Payment API integration code on developer screen with technical documentation
Technical

Payment API in Morocco: Technical Integration Guide 2026

12 min read

Introduction: Why API-First Payment Integration Matters for Moroccan Developers

Morocco's online payment market has reached a technical maturity that now demands robust, programmatic, and scalable integrations. Moroccan merchants are no longer satisfied with generic payment forms that redirect to bank-hosted pages. They want embedded experiences, optimized payment flows, and full control over the customer journey.

The API-first approach meets this requirement. Instead of integrating an opaque widget, the developer interacts directly with a REST API to create payments, manage refunds, store cards securely, and receive real-time notifications. This architecture delivers total flexibility: websites, mobile applications, ERPs, SaaS platforms, and marketplaces can all consume the same API.

This guide is intended for developers, technical architects, and CTOs looking to integrate a payment solution in Morocco via API. We will cover the available API landscape, technical architecture, core endpoints, the 3D Secure flow, webhooks, tokenization, the testing environment, and security best practices. If you are evaluating a payment gateway in Morocco, this guide will give you the technical keys to make the right choice.

Payment API Landscape in Morocco

The Moroccan market offers several payment integration approaches, each with a different level of control and complexity.

Redirect (Hosted Payment Page)

The merchant redirects the customer to a payment page hosted by the provider. This is the traditional approach used by CMI in Morocco. The developer sends transaction parameters via a POST form, the customer enters card details on the provider's page, then is redirected to the merchant site with the result. The advantage is simplicity and PCI compliance (the merchant never touches card data). The downside is the lack of control over the user experience and the drop-off rate associated with the redirect.

Embedded Form (Hosted Fields / Iframe)

The provider delivers secure input fields (hosted fields) that integrate visually into the merchant's form. The customer never leaves the site. Card data is sent directly to the provider via a secure iframe. The merchant retains design control while remaining out of PCI DSS scope for sensitive data storage.

Direct API (Server-to-Server)

The merchant collects card data on the client side (via a secure JavaScript SDK), tokenizes it, then sends the token to their server which calls the provider's API. This is the most flexible approach but requires PCI SAQ A-EP compliance or higher. Chari Pay offers this approach with a client SDK that tokenizes data before any transmission to the merchant's server.

Quick Comparison

CriteriaRedirectHosted FieldsDirect API
UX ControlLowHighTotal
Integration ComplexityLowMediumHigh
PCI ScopeSAQ ASAQ ASAQ A-EP
Conversion RateMediumHighHigh
Integration Time1-2 days3-5 days1-2 weeks

API Architecture: Core Principles

A well-designed payment API rests on standardized technical conventions. Here are the principles to master before starting your integration.

REST and Resources

Modern payment APIs follow the REST paradigm. Each entity (payment, refund, customer, card) is a resource accessible via a dedicated endpoint. Standard operations use HTTP verbs: POST to create, GET to read, PUT/PATCH to update, DELETE to remove.

Authentication

Authentication typically relies on API keys. A pair of keys is provided: a public key (usable on the client side for tokenization) and a secret key (usable only on the server side for sensitive operations). Keys are transmitted via the HTTP header Authorization: Bearer {secret_key}. Some APIs also offer OAuth 2.0 for multi-tenant architectures or marketplace platforms.

Versioning

Serious APIs use explicit versioning, either in the URL (/v1/payments) or in a header (API-Version: 2026-01). Versioning ensures your integration will not break when the API is updated. Check your provider's deprecation policy before starting.

Rate Limiting

APIs enforce request limits to protect infrastructure. Typical limits range from 100 to 1,000 requests per minute depending on the endpoint. Response headers (X-RateLimit-Remaining, X-RateLimit-Reset) allow you to manage client-side throttling. Implement a retry mechanism with exponential backoff to handle 429 (Too Many Requests) responses.

Response Format

Responses are in JSON. Each response includes a standard HTTP code (200 for success, 201 for creation, 400 for validation error, 401 for failed authentication, 404 for resource not found, 500 for server error). The response body contains the created or modified object, with a unique identifier, status, and metadata.

Core Endpoints: The Payment Lifecycle

Payment API integration revolves around a few fundamental endpoints that cover the complete lifecycle of a transaction.

Create a Payment

The POST /v1/payments endpoint creates a payment intent. The request body contains the amount (in centimes), currency (MAD), a unique merchant-side reference, the client return URL, and the webhook notification URL. The response returns a payment object with a unique identifier, a pending status, and depending on the integration mode, a redirect URL or a client_secret for the JavaScript SDK.

Capture a Payment

If you use deferred capture mode (authorize then capture), the POST /v1/payments/{id}/capture endpoint triggers the actual charge after authorization. This mode is useful for merchants who want to verify stock availability or validate an order before charging the customer.

Refund a Payment

The POST /v1/payments/{id}/refunds endpoint creates a full or partial refund. The request body contains the amount to refund (optional for a full refund). Multiple partial refunds are allowed as long as the cumulative amount does not exceed the original amount. The credit timeline to the customer's account depends on the issuing bank (generally 5 to 10 business days in Morocco).

Check Status

The GET /v1/payments/{id} endpoint returns the complete transaction state: status (pending, authorized, captured, refunded, failed), amount, currency, payment method, timestamp, and event history. Use this endpoint for reconciliation and transaction tracking in your back office.

List Transactions

The GET /v1/payments endpoint returns a paginated list of transactions with available filters: date, status, amount, reference. Pagination typically uses a cursor or an offset/limit pair. This endpoint feeds your dashboards, accounting exports, and reporting tools.

3D Secure Flow: Technical Implementation

3D Secure is mandatory in Morocco for online card payments. The technical implementation follows a three-step flow.

Step 1: Initiation

When creating the payment, the API automatically detects that the card requires 3D Secure authentication. The response contains a requires_action status and a next_action object with type redirect_to_3ds and the authentication URL.

Step 2: Authentication

The customer is redirected to their bank's authentication page (or an embedded iframe in 3DS 2.0). They enter the OTP code received via SMS or validate via biometrics. In 3D Secure 2.0, risk analysis can trigger a frictionless flow (no customer intervention) for low-risk transactions.

Step 3: Callback and Finalization

After authentication, the customer is redirected to your return URL. Simultaneously, the webhook notifies your server of the result. Never rely solely on the client redirect to validate the payment. The webhook is the source of truth. Always verify the payment status via the GET endpoint before confirming the order.

Webhooks: Real-Time Notifications

Webhooks are the server-to-server notification mechanism that informs your application of payment events in real time. They are indispensable for a reliable integration.

Configuration

Register a webhook URL in your dashboard or via the API. The URL must be publicly accessible via HTTPS. Select the events you want to receive: payment.completed, payment.failed, payment.refunded, payment.disputed.

Signature Verification

Each webhook is signed with your secret key. The provider includes a signature in the X-Webhook-Signature header. Your server must recalculate the HMAC-SHA256 signature of the request body and compare it to the one received. Never process a webhook without verifying the signature -- this is a critical security vulnerability.

Retry Logic

If your server does not respond with a 2xx code within a defined timeout (typically 5 to 30 seconds), the provider resends the webhook. Retries follow exponential backoff: 1 minute, 5 minutes, 30 minutes, 2 hours, 24 hours. After a maximum number of attempts (typically 5 to 10), the webhook is marked as failed.

Idempotency

The same event may be sent multiple times (retries, network duplicates). Your handler must be idempotent: process each event only once by storing the event identifier and checking whether it has already been processed before executing the business logic. Without idempotency, you risk validating an order twice or sending duplicate confirmation emails.

Tokenization: Storing Cards Securely

Tokenization allows you to store a secure reference (token) to a bank card without handling sensitive data. It is the foundation of one-click payments and recurring subscriptions.

Create a Token

The client-side JavaScript SDK collects card information and sends it directly to the provider's server. In return, it receives a unique token (tok_xxxx) that represents the card. This token is transmitted to your server to create the payment. The merchant never sees the full card number.

Associate a Token with a Customer

The POST /v1/customers/{id}/payment-methods endpoint associates a token with a customer profile. The customer can then find their saved cards on future purchases. The display is limited to the last four digits and the network (Visa, Mastercard).

Token Payment (Recurring)

To charge a saved card, call POST /v1/payments with the payment_method_id instead of a new token. This is the mechanism used for subscriptions, recurring billing, and one-click payments. 3D Secure may be required on the first payment but exempted for subsequent ones if the card has been authenticated and the merchant holds a direct debit mandate.

Sandbox and Testing

No integration should go to production without an exhaustive testing phase. The sandbox environment replicates the production API behavior with fictitious data.

Sandbox Access

The sandbox is typically accessible via a dedicated subdomain (sandbox-api.example.com) or a different base URL. Test API keys are distinct from production keys. All sandbox transactions are simulated and generate no real financial movement.

Test Cards

The provider supplies test card numbers to simulate different scenarios:

  • Successful payment: standard test card, returns a captured status
  • Declined payment: card configured to trigger a decline (insufficient funds, expired card)
  • 3D Secure challenge: card that systematically triggers 3D Secure authentication
  • 3D Secure frictionless: card that passes in frictionless mode without intervention
  • Timeout: card that simulates an exceeded response delay

Scenarios to Test

Before going live, validate each scenario: successful payment, declined payment, full refund, partial refund, network timeout, webhook received, missing webhook, double submission, invalid amount, incorrect currency, and session expiration. Rigorous sandbox testing significantly reduces production incidents.

Security Best Practices

Security is not optional in the payment domain. Here are the essential practices to implement.

Mandatory HTTPS

All communications with the API must transit via HTTPS with TLS 1.2 minimum. Refuse any unencrypted connection. Verify SSL certificates and never disable certificate validation in your code, even in development.

API Key Management

Never store your API keys in source code. Use environment variables or a secrets manager (Vault, AWS Secrets Manager, Azure Key Vault). Differentiate test and production keys. Implement periodic key rotation. Limit each key's permissions to the strict minimum.

PCI DSS Compliance

The PCI scope depends on your integration mode. With client-side tokenization (hosted fields or JavaScript SDK), you are in SAQ A or SAQ A-EP scope, meaning card data never transits through your servers. Document your integration mode and complete the corresponding self-assessment questionnaire.

Input Validation

Systematically validate amounts, currencies, references, and parameters before sending them to the API. Protect your webhook endpoints against injection. Log errors without exposing sensitive data (mask card numbers, never log API keys).

Code Examples: Simplified Payment Flow

Here are pseudocode examples illustrating a basic payment flow and a webhook handler.

Create a Payment (Node.js)

const response = await fetch('https://api.charipay.ma/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CHARIPAY_SECRET_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 15000,        // 150.00 MAD in centimes
    currency: 'MAD',
    reference: 'ORDER-2026-001',
    return_url: 'https://mysite.ma/payment/return',
    webhook_url: 'https://mysite.ma/api/webhooks/payment',
    payment_method: tokenId,  // token obtained via client SDK
  }),
});

const payment = await response.json();

if (payment.status === 'requires_action') {
  // Redirect client to 3D Secure URL
  return redirect(payment.next_action.redirect_url);
}

Webhook Handler (Python)

import hmac
import hashlib

@app.route('/api/webhooks/payment', methods=['POST'])
def handle_webhook():
    payload = request.get_data()
    signature = request.headers.get('X-Webhook-Signature')

    # Verify signature
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        return 'Invalid signature', 401

    event = request.get_json()

    # Check idempotency
    if event_already_processed(event['id']):
        return 'OK', 200

    # Process event
    if event['type'] == 'payment.completed':
        order = get_order(event['data']['reference'])
        order.mark_as_paid()
        send_confirmation_email(order)

    mark_event_processed(event['id'])
    return 'OK', 200

These examples illustrate the fundamental principles. Adapt them to your framework and architecture. Consult the Chari Pay API documentation for full specifications.

How ChariBaaS Accelerates Your Integration

ChariBaaS, through Chari Pay, provides a payment infrastructure designed for Moroccan developers. The REST API is exhaustively documented with examples in multiple languages. The sandbox allows testing all scenarios without risk. JavaScript, PHP, and Python SDKs reduce integration time. Technical support accompanies development teams during integration and beyond.

Whether you are building a Shopify store, a WooCommerce shop, or a custom application, the Chari Pay API offers the flexibility and reliability needed to accept online payments and bank transfers in Morocco.

To start your integration, consult the technical documentation or contact our team for personalized support.

FAQ

What payment APIs are available in Morocco?

Main APIs: Chari Pay (modern REST API, sandbox, full documentation), CMI (e-commerce API, redirect), Payzone (multi-channel API). Chari Pay offers the most complete API with endpoints for payments, refunds, tokenization, recurring billing, and webhooks.

How do I test a payment integration in Morocco?

Use the provider's sandbox environment. Chari Pay provides a full sandbox with test cards, 3D Secure simulation, and test webhooks. Test all scenarios: successful payment, declined, 3D Secure, refund, and timeout.

Are webhooks necessary for a payment integration?

Yes, webhooks are essential. They notify you in real time of transaction results (success, failure, refund). Never rely solely on client-side redirect -- the webhook is the server-side source of truth.

How long does a payment API integration take in Morocco?

With a modern API like Chari Pay: 2-5 days for a basic integration (simple payment), 1-2 weeks for a full integration (recurring, tokenization, webhooks). Documentation and sandbox significantly accelerate the process.

Frequently Asked Questions

What payment APIs are available in Morocco?
Main APIs: Chari Pay (modern REST API, sandbox, full documentation), CMI (e-commerce API, redirect), Payzone (multi-channel API). Chari Pay offers the most complete API with endpoints for payments, refunds, tokenization, recurring billing, and webhooks.
How do I test a payment integration in Morocco?
Use the provider's sandbox environment. Chari Pay provides a full sandbox with test cards, 3D Secure simulation, and test webhooks. Test all scenarios: successful payment, declined, 3D Secure, refund, and timeout.
Are webhooks necessary for a payment integration?
Yes, webhooks are essential. They notify you in real time of transaction results (success, failure, refund). Never rely solely on client-side redirect -- the webhook is the server-side source of truth.
How long does a payment API integration take in Morocco?
With a modern API like Chari Pay: 2-5 days for a basic integration (simple payment), 1-2 weeks for a full integration (recurring, tokenization, webhooks). Documentation and sandbox significantly accelerate the process.