20 min read

Complete Guide to SATIM CIB and Edahabia Payment Integration in Algeria

Step-by-step technical guide covering SATIM API setup, CIB credit card and Edahabia debit card payment flows, error handling, and production deployment for Algerian e-commerce.

SATIM Integration
CIB Payment Algeria
Edahabia Payment
Algeria E-Commerce
Payment Gateway
satim-ts
Node.js Payments

The Algerian Payment Landscape

If you are building an e-commerce platform or any application that accepts online payments in Algeria, you will inevitably encounter SATIM. The Societe d'Automatisation des Transactions Interbancaires et de Monetique (SATIM) is the national electronic payment switch that processes virtually all card-based transactions in Algeria. It sits between merchants, banks, and card networks, acting as the central routing and settlement layer.

Two card types dominate the Algerian market:

  • CIB (Carte Interbancaire): The standard interbank credit/debit card issued by Algerian banks. CIB cards carry the CIB network logo and are accepted at POS terminals and online merchants across the country.
  • Edahabia: Algerie Poste's debit card, linked to CCP (Compte Courant Postal) accounts. With over 20 million CCP accounts in Algeria, Edahabia represents the largest potential payment base in the country.

Both card types are processed through SATIM's payment gateway (sometimes referred to as SATIM e-payment or SATIM IPAY). From a technical standpoint, the integration flow is nearly identical for both. The gateway handles card type detection automatically based on the card number entered by the customer.

Prerequisites

Before writing any code, you need the following:

  1. A merchant account with a bank that supports SATIM e-payment (most major Algerian banks do: BNA, CPA, BEA, BADR, Gulf Bank Algeria, among others).
  2. Terminal ID (format: E010XXXXXX), assigned to identify your merchant terminal. Provided through the SATIM portal.
  3. Username and password for the SATIM gateway API, provided through the SATIM portal after your merchant account is approved.
  4. Test credentials for the sandbox environment at test2.satim.dz, also provided through the SATIM portal.

The onboarding process is handled through the SATIM portal at cibweb.dz. Follow the instructions there to submit your documents and receive your credentials. Timelines vary, so start this process early. If you need help navigating the certification, we offer SATIM certification consulting.

How the Payment Flow Works

SATIM uses a redirect-based payment flow, conceptually similar to 3D Secure or Stripe Checkout. Your server never handles raw card data. Here is the full sequence:

  1. Order Registration: Your backend calls SATIM's register.do endpoint with the order amount, a unique order number, and callback URLs. SATIM responds with an orderId and a formUrl.
  2. Customer Redirect: You redirect the customer's browser to the formUrl. SATIM hosts the payment page where the customer enters their CIB or Edahabia card details.
  3. Payment Processing: SATIM processes the transaction with the issuing bank. The customer may see an OTP/password verification screen (similar to 3DS).
  4. Callback Redirect: After payment (success or failure), SATIM redirects the customer back to your returnUrl or failUrl with the orderId as a query parameter.
  5. Server-Side Confirmation: Your backend calls the acknowledgeTransaction.do endpoint to verify the transaction status. This is the critical step; never trust the client-side redirect alone.
Customer         Your Server         SATIM Gateway         Bank
   |                  |                    |                  |
   |  Place Order     |                    |                  |
   |----------------->|                    |                  |
   |                  |  register.do       |                  |
   |                  |------------------->|                  |
   |                  |  orderId + formUrl |                  |
   |                  |<-------------------|                  |
   |  Redirect to     |                    |                  |
   |  formUrl         |                    |                  |
   |<-----------------|                    |                  |
   |  Enter card info |                    |                  |
   |---------------------------------------->|                |
   |                  |                    |  Process payment |
   |                  |                    |----------------->|
   |                  |                    |  Auth response   |
   |                  |                    |<-----------------|
   |  Redirect to     |                    |                  |
   |  returnUrl       |                    |                  |
   |<-----------------------------------------|              |
   |  Page loads      |                    |                  |
   |----------------->|                    |                  |
   |                  | acknowledgeTransaction.do             |
   |                  |------------------->|                  |
   |                  | Payment status     |                  |
   |                  |<-------------------|                  |
   |  Order confirmed |                    |                  |
   |<-----------------|                    |                  |

Setting Up with satim-ts

The @bakissation/satim package is a production-grade TypeScript SDK that wraps the SATIM API with strict types, input validation, automatic amount conversion, and comprehensive error handling.

Installation

1npm install @bakissation/satim

The SDK supports both ESM and CommonJS, requires Node.js 18 or later, and has zero external dependencies (it uses the native fetch API).

Configuration

The simplest approach is environment variables. Create a .env file:

1SATIM_USERNAME=your_merchant_username 2SATIM_PASSWORD=your_merchant_password 3SATIM_TERMINAL_ID=E010XXXXXX 4SATIM_API_URL=https://test2.satim.dz/payment/rest

Then initialize the client:

1import { createSatimClient, fromEnv } from '@bakissation/satim'; 2 3const satim = createSatimClient(fromEnv());

For more explicit control, pass the configuration directly:

1import { createSatimClient, API_BASE_URLS } from '@bakissation/satim'; 2 3const satim = createSatimClient({ 4 userName: process.env.SATIM_USERNAME!, 5 password: process.env.SATIM_PASSWORD!, 6 terminalId: process.env.SATIM_TERMINAL_ID!, 7 apiBaseUrl: API_BASE_URLS.TEST, // switch to API_BASE_URLS.PRODUCTION for live 8 language: 'fr', 9 currency: '012', // DZD (ISO 4217) 10});

Implementing the Payment Flow

Step 1: Register the Order

When your customer is ready to pay, create an order on your backend:

1import { createSatimClient, fromEnv } from '@bakissation/satim'; 2import { randomUUID } from 'crypto'; 3 4const satim = createSatimClient(fromEnv()); 5 6async function createPayment(orderNumber: string, amountDzd: number) { 7 const response = await satim.register({ 8 orderNumber, // Max 10 chars, must be unique per transaction 9 amount: amountDzd, // In DZD (minimum 50 DZD), auto-converted to minor units 10 returnUrl: 'https://yoursite.com/payment/callback', 11 failUrl: 'https://yoursite.com/payment/failed', 12 description: 'Purchase from YourStore', 13 udf1: orderNumber, // Required: your internal reference 14 idempotencyKey: randomUUID(), // Prevents duplicate orders on retry 15 }); 16 17 if (response.isSuccessful()) { 18 // Save response.orderId to your database, linked to the order 19 return { 20 orderId: response.orderId, 21 redirectUrl: response.formUrl, 22 }; 23 } 24 25 throw new Error('Failed to register order with SATIM'); 26}

Key points about the register call:

  • Amount handling: Pass amounts in DZD as whole numbers or decimals (e.g., 5000 for 5,000 DZD, or 806.5 for 806.50 DZD). The SDK automatically converts to minor units (centimes) as required by the API.
  • Order number: Maximum 10 characters. Must be unique per transaction. If you reuse an order number, SATIM will return error code 1.
  • udf1: Required by SATIM. Use it for your internal reference (invoice number, order ID, etc.).
  • Idempotency: Always pass an idempotencyKey in production to prevent duplicate charges if your request is retried due to network issues.

Step 2: Redirect the Customer

On your frontend, redirect the customer to the formUrl returned by the register call:

1// In your API response handler (frontend) 2window.location.href = redirectUrl;

Or if you are building an API-first backend, return the URL to your frontend/mobile client and let it handle the redirect. The SATIM payment page supports French, English, and Arabic, configurable via the language parameter.

Step 3: Handle the Callback

After the customer completes (or abandons) the payment, SATIM redirects them to your returnUrl or failUrl with an orderId query parameter. On your callback endpoint, verify the payment server-side:

1import { OrderStatus, interpretOrderStatus } from '@bakissation/satim'; 2 3async function handlePaymentCallback(orderId: string) { 4 const status = await satim.confirm(orderId); 5 6 if (status.isPaid()) { 7 // Payment successful, orderStatus === 2 (DEPOSITED) 8 console.log('Payment confirmed for order:', status.orderNumber); 9 console.log('Amount:', status.amount); 10 console.log('Card (masked):', status.pan); // e.g., 6280****7215 11 12 // Update your order status in the database 13 // Deliver the product/service 14 return { success: true, orderNumber: status.orderNumber }; 15 } 16 17 // Payment not successful 18 console.log('Payment status:', interpretOrderStatus(status.orderStatus)); 19 console.log('Details:', status.actionCodeDescription); 20 return { success: false, reason: status.actionCodeDescription }; 21}

The confirm method (aliased as getOrderStatus) calls SATIM's acknowledgeTransaction.do endpoint. This is the only reliable way to know if a payment succeeded. Never rely solely on the redirect URL the customer landed on, as it can be spoofed or manipulated.

Step 4: Refunds (When Needed)

To refund a completed transaction:

1async function refundPayment(orderId: string, amountDzd: number) { 2 const result = await satim.refund(orderId, amountDzd); 3 4 if (result.isSuccessful()) { 5 console.log('Refund processed successfully'); 6 return true; 7 } 8 9 console.error('Refund failed:', result.errorMessage); 10 return false; 11}

Refunds must reference the original orderId returned during registration. Partial refunds are supported by passing a smaller amount than the original transaction.

CIB vs Edahabia: What Developers Need to Know

From an API integration perspective, CIB and Edahabia payments are handled identically by the SATIM gateway. You do not need to specify the card type when registering an order. The gateway determines the card type from the card number the customer enters on the payment page.

There are a few practical differences to be aware of:

  • Card number format: CIB cards typically start with 6280 (16 digits). Edahabia cards follow Algerie Poste's numbering scheme. Both are processed through the same register.do and acknowledgeTransaction.do endpoints.
  • Transaction limits: Edahabia cards may have lower daily transaction limits compared to CIB cards, depending on the cardholder's configuration with Algerie Poste. Your application should gracefully handle "limit exceeded" declines.
  • Settlement timelines: Settlement to your merchant account may differ slightly between CIB and Edahabia transactions, depending on your acquiring bank's arrangement. This is a banking operations concern, not a code concern.
  • OTP verification: Both card types may require an OTP or password entry on the SATIM payment page. The password field on the test cards is used for this purpose in the sandbox.

If you specifically need to handle bill payments or a particular transaction type, you can use the fundingTypeIndicator parameter (e.g., 'CP' or '698'), but for standard e-commerce purchases, this is not required.

Error Handling

The SDK provides typed error classes for every failure scenario. Robust error handling is especially important for payment integrations where silent failures can lead to lost revenue or double charges.

1import { 2 SatimApiError, 3 ValidationError, 4 HttpError, 5 TimeoutError, 6 ConfigError, 7 mapSatimErrorCode, 8} from '@bakissation/satim'; 9 10async function safePayment(orderNumber: string, amount: number) { 11 try { 12 const response = await satim.register({ 13 orderNumber, 14 amount, 15 returnUrl: 'https://yoursite.com/payment/callback', 16 udf1: orderNumber, 17 idempotencyKey: crypto.randomUUID(), 18 }); 19 return response; 20 } catch (error) { 21 if (error instanceof ValidationError) { 22 // Bad input: invalid amount, missing fields, etc. 23 console.error(`Validation error [${error.code}]:`, error.message); 24 } else if (error instanceof SatimApiError) { 25 // SATIM rejected the request 26 console.error(`SATIM error [${error.satimErrorCode}]:`, error.message); 27 } else if (error instanceof TimeoutError) { 28 // Request timed out, safe to retry with same idempotency key 29 console.error(`Timeout after ${error.timeoutMs}ms`); 30 } else if (error instanceof HttpError) { 31 // Network or HTTP-level failure 32 console.error(`HTTP error [${error.httpStatus}]:`, error.message); 33 } else if (error instanceof ConfigError) { 34 // Missing or invalid configuration 35 console.error('Config error, missing keys:', error.missingKeys); 36 } 37 throw error; 38 } 39}

SATIM Error Code Reference

These are the error codes returned by the SATIM API across its endpoints:

Coderegister.doacknowledgeTransaction.dorefund.do
0SuccessSuccessSuccess
1Order already processed--
2-Payment credentials error-
3Unknown currency--
4Required param missing--
5Invalid parameterAccess deniedAccess denied / Invalid amount
6-Unregistered orderUnregistered order
7System errorSystem errorSystem error
14Invalid paymentway--

Order Status Codes

After calling confirm() or getOrderStatus(), check the orderStatus field:

CodeMeaningAction
0Registered but not paidCustomer abandoned or has not completed payment yet
-1Unknown declineContact SATIM support if persistent
1Approved (pre-authorization held)Awaiting deposit
2Deposited (payment complete)Fulfill the order
3Authorization reversedPayment was reversed before settlement
4RefundedTransaction was refunded
6DeclinedCard was declined by the issuing bank

Testing with the SATIM Sandbox

SATIM provides a sandbox environment at https://test2.satim.dz/payment/rest for integration testing. Use the following test cards:

Card NumberCVV2ExpiryPasswordScenario
628058111000721537301/2027123456Successful payment
628058111000671289701/2027123456Temporarily blocked card
628058061006111026001/2027123456Insufficient balance
628058061006121904901/2027123456Limit exceeded
628058111000651420501/2027123456Incorrect CVV2
628058061006101199201/2027123456Valid credit card

When testing:

  1. Set your SATIM_API_URL to https://test2.satim.dz/payment/rest.
  2. Use the test credentials provided by your bank (not your production credentials).
  3. Test every scenario: successful payment, declined card, insufficient balance, timeout handling, and duplicate order prevention.
  4. Verify that your confirm() call correctly interprets each order status.
  5. Test the full user journey, including what happens when the customer closes the browser on the SATIM payment page without completing the transaction.

Production Deployment Checklist

Before going live, work through this checklist:

Configuration

  • Switch SATIM_API_URL to https://satim.dz/payment/rest
  • Use production credentials (username, password, terminal ID) from your bank
  • Store all credentials in environment variables, never in source code
  • Ensure .env files are in .gitignore
  • Set NODE_ENV=production to disable verbose dev logging

Security

  • Use POST method for all SATIM API calls (the SDK defaults to this)
  • Always verify payment status server-side via confirm(), never trust client-side redirects
  • Serve your callback URLs over HTTPS only
  • Implement idempotency keys on every register() call to prevent duplicate charges
  • Never log or store full card numbers (the SDK never exposes them)

Reliability

  • Handle all error types (SatimApiError, TimeoutError, HttpError, ValidationError)
  • Implement retry logic for TimeoutError scenarios (using the same idempotency key)
  • Set up monitoring/alerting for failed payments
  • Log transaction results (using the SDK's built-in logger or your own via the customLogger option)
  • Store the SATIM orderId in your database for every transaction, enabling future status checks and refunds

Testing

  • Run end-to-end tests against the sandbox before switching to production
  • Test with all sandbox card scenarios (success, decline, insufficient funds, blocked)
  • Verify refund flow works correctly
  • Test what happens when SATIM is unreachable (timeout handling)

Compliance

  • Verify with your bank that your integration is approved for production use
  • Ensure your terms of service and privacy policy cover electronic payments
  • Keep records of all transactions as required by Algerian commerce regulations

Advanced: Integrating with Fastify

If you are using Fastify as your web framework, the @bakissation/fastify-satim plugin provides a streamlined integration that registers the SATIM client as a Fastify decorator:

1npm install @bakissation/fastify-satim
1import Fastify from 'fastify'; 2import satimPlugin from '@bakissation/fastify-satim'; 3 4const app = Fastify(); 5 6app.register(satimPlugin, { 7 userName: process.env.SATIM_USERNAME!, 8 password: process.env.SATIM_PASSWORD!, 9 terminalId: process.env.SATIM_TERMINAL_ID!, 10 apiBaseUrl: 'https://satim.dz/payment/rest', 11}); 12 13app.post('/pay', async (request, reply) => { 14 const { orderNumber, amount } = request.body as any; 15 16 const result = await app.satim.register({ 17 orderNumber, 18 amount, 19 returnUrl: 'https://yoursite.com/payment/callback', 20 udf1: orderNumber, 21 }); 22 23 if (result.isSuccessful()) { 24 return reply.redirect(result.formUrl!); 25 } 26 27 return reply.status(500).send({ error: 'Payment registration failed' }); 28});

This avoids manual client instantiation and ensures the SATIM client lifecycle is managed by Fastify.

Need Help with Your Integration?

Integrating payments is high-stakes work where bugs translate directly into lost revenue or compliance issues. If you need expert help with your SATIM CIB/Edahabia integration, from initial setup and bank coordination to production deployment and ongoing support, I offer dedicated consulting for Algerian payment systems.

Get in touch for SATIM integration consulting

© 2026 Abdelbaki Berkati. All rights reserved.