Open Source••16 min read

SATIM CIB & Edahabia: Certification, API, Logos

What it actually takes to accept CIB and Edahabia payments directly in Algeria: the CIBWEB file, three certification attempts, the bank contract, and the open-source stack I built from what was missing.

SATIM certification
CIB Edahabia payment integration
CIBWEB
GIE Monétique
Algeria payment gateway
TypeScript SDK
open source fintech

Most Algerian businesses that take card payments online never deal with SATIM directly. They go through an intermediary that holds its own merchant account, pay a commission on every sale, and get paid after the intermediary does. I wanted the direct route for Tutorios, the learning platform we build at IdeaCrafters: our own certification, our own bank, money settling straight into our own account.

If you're looking for how online payment in Algeria really works for a merchant (the SATIM payment gateway, CIB and Edahabia cards, the web marchand certification, the e-paiement contract with your bank), this is the full path as we lived it, from opening the file on CIBWEB to the bank contract: the steps, the reasons we were rejected, and the code I ended up writing because the tooling for this didn't exist.

Who does what

Three parties are involved, and most confusion comes from mixing them up:

  • GIE Monétique runs the rules and the CIBWEB portal (cibweb.dz). It accepts your file, issues the certification, and authorizes you to go live.
  • SATIM runs the payment platform. It gives you test credentials, runs the certification session with you, and eventually issues your production merchant identifier.
  • Your bank (the acquiring bank) signs the merchant contract with you and receives the money on your business account. Payments cannot land on a personal account or a CCP.

You talk to all three, at different moments, and none of them owns the whole process.

The official order

SATIM's integration page and the banks' merchant guides describe the same sequence:

  1. Register on cibweb.dz and file an integration request with your commercial register (RC) attached.
  2. GIE Monétique reviews the request. The announced delay is 24 hours.
  3. You get a test slot, integrate against SATIM's certification platform, then pass a certification session with SATIM.
  4. GIE Monétique issues the certification and the authorization to go live.
  5. Your bank checks your account domiciliation and signs the merchant contract (banks call it the contrat d'adhésion; some call it a remote-sales contract).
  6. The bank sends your configuration to SATIM, SATIM issues your merchant ID, and the bank registers it on its side. Then you're live.

Older material from GIE Monétique says the process starts at the bank. In practice, the bank came last for us: SATIM only asked about the bank contract after certification was done.

Where the time actually went

SATIM was fast every time we needed them. GIE Monétique answers a CIBWEB request within a day, SATIM's certification team reported every issue precisely with screenshots, and they retested the same day we said something was fixed. When the gateway hiccuped during our final session, it was back within the hour.

Our delays came from our side, and mostly from one thing: a bad handoff. A colleague opened the CIBWEB file, then moved on, and the context didn't move with the file. Test credentials expired in between, the wrong URL went out, and SATIM's remarks sat unanswered while we worked out who owned the file. If you take one lesson from this article, make it this: one named owner for the SATIM file, from the first form to the bank contract.

Step 1: the CIBWEB file

The request itself is simple: an account on cibweb.dz, a form, and your RC. What the form doesn't tell you is how the rest of the process works.

A slot gives you test days plus one certification day. When I went through it, the console listed 25 test days for merchants and 15 for developers, with extra days billed at around 5,000 DA each. Your test credentials are tied to that slot, and they expire. Ours expired during the handoff, before the first certification attempt, which is why that attempt failed to reach SATIM at all.

Book the certification day only when you're actually done. The session is for verifying a finished integration, not for building one.

Step 2: the "payment procedure"

Before testing, SATIM asks you to send your procédure de paiement: the exact steps a tester follows to reach the payment page on your site. Treat it like a test script for someone who has never seen your product:

  • the production URL (not staging, more on that below)
  • test accounts with passwords
  • which product to buy and at what price
  • every click until the redirect to SATIM

We later sent three separate student accounts on three different course pages, with the monthly and quarterly price for each. That saved a lot of back and forth.

Step 3: certification, and why we failed twice

The certification checklist is public enough (I documented it in the satim-ts certification docs), but the real failures were in the details.

First attempt, rejected:

  • We had sent our staging URL. SATIM certifies the site you'll actually run, so the domain on the report is your production domain (ours is app.tutorios.net).
  • The contact number on the site was an old one.
  • No general terms of payment and sale on the payment page. SATIM requires them displayed before payment, with an explicit acceptance (we added a mandatory checkbox linking to the full terms, in French and Arabic).
  • The site didn't route to SATIM, because our test credentials had expired.

Second attempt, rejected:

  • SATIM's toll-free number (3020) was visible during the payment flow. It belongs on the return page and the receipt only.
  • udf1 wasn't reaching their server. It's mandatory: up to 20 alphanumeric characters, no special characters.
  • The "email me the receipt" button didn't work.
  • The receipt was missing the transaction number, the authorization number, the time of the transaction, and the 3020 number.

That attempt was closed because we didn't reply with the fixes in time, a direct cost of the handoff. Reply to every remark, even with "fixed, please retest".

Final session, certified the same day:

  • The tester couldn't find the payment page at first (a deploy had moved it).
  • The CAPTCHA didn't render on their machine, so the pay button stayed disabled.
  • The payment page expired during a maintenance window on our side.
  • A blocked card produced a server error instead of a clean rejection with the response code.
  • The order number was missing from the receipt.
  • They asked us to hide transaction details on the rejected return page, and to show the transaction identifier correctly on the accepted one.
  • Mid-session, our own test calls started returning error 5 ("access denied") from the gateway. SATIM had it restored within the hour.

We fixed each item live, SATIM retested right away, and the certification was granted that afternoon.

The rules that actually get checked

From our certification report, the things SATIM verifies on your site:

Before payment

  • Valid SSL.
  • The final amount, visibly emphasized (bold, bigger), e.g. Montant : 1 500,00 DA.
  • General payment terms (agreed with your bank) and your sale terms, accepted explicitly before paying.
  • A CAPTCHA on the page with the pay button.
  • The CIB / Edahabia logo on the button that redirects to SATIM.
  • The redirect opens SATIM's page in an independent browser context, not an iframe.
  • One language across the whole flow: summary, redirect, return page, receipt, error messages.

Return page, accepted payment

  • respCode_desc, orderId (SATIM's transaction id), orderNumber (yours), approvalCode
  • date and time, amount and currency, payment method (CIB / Edahabia)
  • the 3020 number
  • a receipt you can print, download as PDF, and email as PDF

Return page, rejected payment

  • respCode_desc, falling back to actionCodeDescription when it's empty
  • the 3020 number

Card scenarios, run with SATIM's test cards: a valid card must pass, and these must all be refused cleanly: temporarily blocked, lost, stolen, wrong expiry date, card unknown to the issuer, card limit exceeded, insufficient balance, wrong CVV2, wrong password, three wrong passwords, card not enabled for online payment, card inactive for online payment, terminal ceiling exceeded, expired card. A refund and a cancellation from SATIM's platform are tested too.

The logos you need

Two visuals are checked during certification: the CIB / Edahabia logo on the button that sends the buyer to SATIM, and SATIM's toll-free number on the return page and the receipt. SATIM asked us to show the 3020 number as the official image rather than plain text.

Most copies of these logos floating around are small, blurry PNGs. I rebuilt them as vectors: the CIB mark comes straight from GIE Monétique's own vector artwork, the Algérie Poste mark from its official SVG. They stay sharp at any size, on light or dark backgrounds.

CIB and Edahabia logo for the payment button

CIB / Edahabia payment button logo: SVG · PNG

SATIM 3020 toll-free number logo

SATIM 3020 toll-free logo: SVG · PNG

Separate marks, if your design needs them: CIB SVG · PNG, Edahabia SVG · PNG.

Download all logos (ZIP, SVG + PNG)

These marks belong to GIE Monétique, SATIM and Algérie Poste; use them as the certification rules require.

The certificate is issued by GIE Monétique and is valid for two years.

Step 4: getting the report out of CIBWEB

One portal step tripped us up. To request production, SATIM asked us to open the "Certification et validation" tab, start the integration test, scroll to the bottom and click "Confirmer" to display the certification report.

For us, that page redirected to the profile, and once it loaded, "Confirmer" wasn't clickable. We also started a non-regression request by mistake while looking for the button, which then had to be cancelled. SATIM escalated the portal bug to GIE Monétique right away (CIBWEB is theirs, not SATIM's), and the report came through once the portal was fixed.

If you're stuck on a portal screen, send screenshots right away and ask SATIM to escalate to GIE Monétique; they will.

Step 5: the bank contract

Once we had the report, SATIM's next question was short: have you signed your contract with your bank?

That's the step that turns a certified integration into a live one. Your bank checks that your business account is domiciled with them, signs the merchant contract with you, and sends your configuration to SATIM. SATIM then issues the production merchant identifier, and the bank registers it on its side. Fees and per-transaction commissions are set by each bank, so ask for them in writing when you sign.

Two practical points:

  • Production is a different gateway. Certification runs on test2.satim.dz, the staging environment for certified merchants is test.satim.dz, and production is cib.satim.dz. satim.dz itself is SATIM's corporate site and returns HTML 404s on /payment/rest. Several libraries ship that wrong production default, mine included, so set the production URL explicitly.
  • Certification credentials don't work in production. A real register.do against cib.satim.dz with certification credentials returns error 5, "access denied". Note that getOrderStatusExtended.do also returns error 5 for any order that doesn't exist, valid credentials or not, so it can't be used to test credentials.

At the time of writing, this is the step we're on. I'll update this section with the bank side once we're live.

The SATIM API in one page

SATIM's gateway (SATIM-IPAY) is a small REST API, and its documentation lives inside the CIBWEB console rather than on a public site. I mirrored the full reference in the satim-ts gateway docs. The essentials:

EnvironmentBase URLUsed for
Certificationhttps://test2.satim.dz/payment/restIntegration and certification tests
Staginghttps://test.satim.dz/payment/restOngoing tests once you're certified
Productionhttps://cib.satim.dz/payment/restReal payments

The payment flow uses three endpoints:

  1. register.do registers the order and returns an orderId and a formUrl, SATIM's hosted payment page. You send the amount in centimes, the currency 012 (DZD), the language (AR, FR or EN), your return URL, and a jsonParams object carrying force_terminal_id (your terminal ID from the bank) and udf1.
  2. public/acknowledgeTransaction.do confirms the order after the buyer comes back and returns its status. If you never call it, SATIM cancels the order after a short timeout.
  3. refund.do refunds a paid order, fully or in parts, never more than what was paid.

The statuses you'll actually handle: 0 registered but not paid, 2 paid, 3 authorization reversed, 4 refunded, 6 declined. Use POST for every call, even though the gateway also accepts GET, so credentials never end up in URLs or logs.

The code: what was missing

I started the SDK while the file was open, because there was no maintained, typed, direct SATIM client for JavaScript: only intermediaries charging for what is a few HTTP calls, and old packages without types or sane error handling. Certification then showed me everything around those calls that every integrator rebuilds badly. So the stack grew in layers, each one published separately.

@bakissation/satim: the gateway client

One typed method per gateway endpoint: register, getOrderStatus (confirm), refund. It enforces the gateway's rules before sending anything: order numbers up to 10 alphanumeric characters, udf1 up to 20, a minimum of 50 DA. It maps SATIM's numeric error codes to readable errors, never logs credentials, and loads configuration from environment variables.

typescript
import { createSatimClient, fromEnv } from '@bakissation/satim'; const satim = createSatimClient(fromEnv()); const reg = await satim.register({ orderNumber: 'A1B2C3D4E5', amount: 1500, returnUrl: 'https://app.example.dz/payment/return', udf1: 'INV0001', }); // redirect the buyer to reg.formUrl

@bakissation/fastify-satim: the server plugin

For Fastify backends: the client as a decorator, schema-validated opt-in routes for register, confirm, refund and status, and multi-tenant support, where each merchant on a platform uses their own SATIM credentials. It works with Fastify 4 and 5.

@bakissation/dinar: money without float bugs

SATIM wants amounts in centimes, and converting by hand is where real bugs live. Months later I reviewed a payment layer that converted to centimes twice and sent the gateway a hundred times the intended amount; it was caught in testing, and it's exactly the class of bug a money type removes. Dinar stores integer centimes, rounds correctly for VAT, splits totals without losing a centime, and formats and parses 1 234,56 DA in French and Arabic. The SDK now takes Dinar amounts directly.

@bakissation/tasdid: the payment lifecycle

This is the layer certification taught me the most about. SATIM has no webhooks, and it auto-cancels an order you don't confirm within about 20 minutes. The return URL is just a browser redirect, so the buyer can close the tab, lose their connection, or come back twice. If you trust the redirect, you'll eventually ship an order that wasn't paid, or miss one that was.

tasdid treats the gateway's order status as the only source of truth:

created → pending → paid | failed | expired
paid → partially_refunded → refunded
  • start registers idempotently and returns the redirect URL.
  • handleReturn verifies the result against the gateway; it never trusts the redirect.
  • reconcile and reconcilePending sweep pending payments from a cron, which is the only health signal you get without webhooks.
  • Refunds are guarded: never more than was paid, never twice for the same key.
  • Storage is pluggable (Postgres, Redis, Prisma, or your own), and every transition fires an event you can push to a queue.

Because the card is only ever entered on SATIM's page, the merchant stays in PCI DSS SAQ-A by construction.

@bakissation/tasdid-adapters: routes for any framework

Mounts start, return, reconcile and refund as routes on the Web Fetch API: Next.js App Router, Hono, Remix, SvelteKit, Cloudflare Workers, Bun, Deno.

@bakissation/satim-testing: a local SATIM

SATIM's certification platform is remote, gated behind slot credentials that expire, and unpredictable, so it's useless for automated tests. satim-testing is a deterministic stand-in for the gateway: a drop-in client double with scriptable outcomes, the official certification test cards, and the certification scenarios as a ready-made end-to-end checklist. It also runs as an HTTP simulator with a payment page a browser can drive, so Playwright or Cypress can walk your real checkout in CI. Our second rejection (missing receipt fields, a broken email button) is exactly what this catches before a SATIM tester does.

How they fit together

@bakissation/dinar            money type, zero dependencies
└── @bakissation/satim        gateway client
    ├── @bakissation/fastify-satim    Fastify plugin
    └── @bakissation/tasdid           payment lifecycle
        └── @bakissation/tasdid-adapters   Fetch API routes
@bakissation/satim-testing    test double for satim and tasdid (dev only)

All of them are MIT licensed, published with provenance, and on GitHub.

If you're starting now

  • Open the CIBWEB file early. It costs nothing to wait on, and slot credentials take time.
  • Build and test against a local double, and book certification only when the checklist above passes end to end.
  • Certify on your production domain, with your real contact details and your terms in place.
  • Write the payment procedure like a test script, with ready-made accounts.
  • Answer every remark from SATIM the same day.
  • Talk to your bank about the merchant contract while certification is running, so it's ready the day you're certified.
  • Give the whole file one owner, start to finish.

FAQ

How long does SATIM certification take? On SATIM's side, not long. BDL publishes 15 days once the merchant's site is finished, and our final session was certified the same afternoon. Most of the delay people experience comes from unfinished integrations and slow replies, which was our case.

Do I need a commercial register to accept CIB and Edahabia payments? Yes. The CIBWEB request requires your commercial register (RC), and payments settle to a business bank account. Personal accounts and CCP accounts can't receive them.

Can I accept Edahabia cards as well as CIB? Yes. Algérie Poste's Edahabia cards go through the same SATIM gateway as bank-issued CIB cards, so one integration covers both.

Does the SATIM gateway have webhooks? No. Your server has to confirm each order with acknowledgeTransaction.do, and you should run a reconciliation job for buyers who never come back to your return page.

Can I embed the SATIM payment page in an iframe? No. Certification requires the payment page to open in an independent browser context. A full redirect also keeps card data off your servers entirely.

Should I integrate directly or use a payment intermediary? An intermediary is faster to start with, but it takes a commission on every payment, sits between you and your money, and you don't hold your own certification. If online payments are core to your business, the direct route through CIBWEB, SATIM and your bank is worth it.

Is there a JavaScript or TypeScript SDK for SATIM? Yes, the open-source packages above: @bakissation/satim for the gateway, @bakissation/tasdid for the full payment lifecycle, and @bakissation/satim-testing to test it all without a SATIM account.