An HR administrator at a mid-sized Saudi establishment opens three screens every morning: the internal HR system, the Muqeem portal, and a spreadsheet of iqama expiry dates. The spreadsheet is the real source of truth. When it is wrong, the company finds out on the day an employee is standing at an airport gate with an exit/re-entry visa that was never successfully issued.
This is not an administrative discipline problem. It is an architectural one: employee state is spread across three government systems, none of which talks to yours automatically — and one of them, Muqeem, does not expose a self-service API at all.
This article covers what "Muqeem integration" actually means in engineering terms, why most of what is sold under that name is access resale rather than integration, and how to build the layer you actually need.
What Muqeem is, and why it is not Qiwa or Mudad
Muqeem is operated by Elm Company in cooperation with the General Directorate of Passports (Jawazat). Its domain is everything passport- and residency-related for expatriate workers:
- Issuing, renewing, and transferring iqamas
- Exit/re-entry visas: issue, cancel, extend, reprint
- Final exit visas
- Passport data updates and validity extension
- Resident status reports and visa verification
The common mistake is treating Muqeem, Qiwa, and Mudad as three interchangeable portals. They are not. Each has a different owning authority and a different scope:
| Platform | Authority | Scope |
|---|---|---|
| Muqeem | Jawazat / Elm | Residency, passports, exit visas |
| Qiwa | Ministry of HRSD | Work permits, Nitaqat, contracts |
| Mudad | SAMA / banks | Payroll, wage protection |
That distinction is not taxonomy. It is execution ordering, and it is the core of the engineering problem.
The dependency chain that breaks most integrations
Muqeem transactions are not independent. There is a strict order, and ignoring it is the number one cause of rejections:
Valid work permit (Qiwa)
↓
Iqama renewal (Muqeem)
↓
Exit/re-entry visa (Muqeem)
↓
Passport validity covers the period
Renewing an expatriate employee's iqama requires a valid work permit from Qiwa. Work permit fees are paid through Qiwa; residency fees are paid through Muqeem via a SADAD biller code. Two systems, two separate payment rails, one state that must agree.
The practical consequence: your system cannot treat "renew the iqama" as a single call. It has to verify the first condition before attempting the second — otherwise you pay for a rejected transaction and leave your own records claiming a success that never happened.
This is precisely the pattern we covered in Qiwa integration for HR systems, which is the prerequisite for any Muqeem work.
The uncomfortable truth: there is no public API
Search for "Muqeem API" and you will find dozens of results: Odoo modules, Jisr and ZenHR and Menaitech integrations, firms selling "instant connection." What you will not find is official public endpoint documentation.
The reason is that Muqeem does not expose a self-service API. Programmatic access runs through Elm's official integration channels — the Rabet platform or an equivalent integrator package — and requires:
- An active Muqeem establishment subscription of the comprehensive type (an operations-only package is not sufficient for integration)
- Integration permission enabled on the establishment account
- Official credentials issued in the establishment's name, not the vendor's
- An additional cost on top of the subscription — vendor sources indicate a range of 12–20% above subscription value to enable the link
- A points model: every transaction consumes credit from the establishment's package
Point three is the commercially important one and the most frequently glossed over. The credentials belong to the establishment. When a vendor sells you "Muqeem integration," they are usually building a connector on top of your own subscription. That is a legitimate service — but it means the connection is not a proprietary feature of their product. It is something you own and can move.
If a vendor tells you Muqeem integration is available exclusively through their product, ask whose name the credentials will be issued in. The answer tells you whether you are buying an integration or renting access.
Where integrations actually fail
Across a series of Saudi government platform integration projects, the failures repeat in four shapes — and none of them are about code quality:
1. Silent state drift
Your HR system stores iqama expiry as a field. Jawazat is the source of truth. If an iqama is renewed manually through the portal, or a visa is cancelled, or a sponsorship is transferred, your field is now wrong and nothing tells you.
The fix is not smarter sync logic. It is periodic reconciliation: pull the resident status report, compare it to local state, and record every difference as an alert rather than silently overwriting it.
type MuqeemState = {
iqamaNumber: string;
iqamaExpiry: string; // Hijri at the source — convert once at the boundary
passportExpiry: string;
exitReentryStatus: 'none' | 'active' | 'expired';
};
// Do not overwrite local state. Surface the differences.
function reconcile(local: MuqeemState, remote: MuqeemState) {
const drift = (Object.keys(remote) as Array<keyof MuqeemState>)
.filter((k) => local[k] !== remote[k])
.map((field) => ({ field, local: local[field], remote: remote[field] }));
return drift.length
? { status: 'drift' as const, drift, authority: 'muqeem' }
: { status: 'in_sync' as const };
}2. The Hijri calendar
Iqama dates are Hijri. Your system is almost certainly Gregorian. Converting at every render is a recipe for off-by-one-day errors — and a one-day error on an iqama expiry date is a fine.
The rule: convert once at the system boundary and store both. Display Hijri, because that is what the user and the authority speak, and compute in Gregorian.
3. Points exhausted mid-operation
Point packages run out. When they do, transactions fail — but not necessarily in a way your system distinguishes from a validation failure. If your connector retries automatically on every error, you either burn log entries for nothing or fire a duplicate transaction the moment the balance is topped up.
Separate balance errors from validation errors from network errors. The first needs a human alert, the second must never be retried, and only the third deserves a retry.
4. No idempotency
Issuing an exit/re-entry visa twice is not a cosmetic bug — it is a fee paid twice and a state that needs manual cancellation. Any operation that mutates state at Jawazat must carry a uniqueness key from your side, recorded before the call rather than after.
// Record the intent before the call, not after the response.
async function issueExitReentry(employeeId: string, days: number) {
const key = `exit-reentry:${employeeId}:${days}:${businessDate()}`;
if (await ledger.has(key)) {
return ledger.get(key); // Already executed — do not call again
}
await ledger.reserve(key); // Survives a dropped connection
const result = await gateway.call('exit-reentry/issue', { employeeId, days });
await ledger.settle(key, result);
return result;
}A network drop after the request is sent but before the response arrives is the case that produces duplicates. Reserving first makes that case detectable instead of expensive.
The architecture we recommend
The common path — pushing Muqeem logic into the HR system or an Odoo module — looks faster and becomes more expensive. Any change in government rules turns into an upgrade of the whole system.
The alternative is a thin middleware layer that you own:
HR system / Odoo / your internal platform
↓ (stable internal interface)
Compliance layer (you own this)
↓
Elm gateway / Rabet → Muqeem → Jawazat
What you gain: dependency checks in one place, a transaction ledger independent of your vendor's release cycle, the ability to replace the front-end system without rebuilding compliance, and an audit trail that survives review.
This is the same argument we made in the ERP trap: integration, not replacement, and the same layer that serves Mudad payroll integration. Build it once, connect three platforms to it.
A note on personal data
Residency and passport data is personal data under the Saudi PDPL. Iqama numbers, passport images, and visa dates are not ordinary fields.
Practically: minimise what you store locally to what the workflow requires, keep a record of who did what and when, and pay close attention to where the middleware runs if it sits on a cloud outside the Kingdom. We covered the constraints in cross-border data transfer under the PDPL.
Checklist before you start
- Establishment subscription is the comprehensive type with integration enabled
- Credentials issued in the establishment's name, not the vendor's
- Integration activation cost and points consumption model documented in writing
- Qiwa work permits valid before any iqama renewal attempt
- Hijri/Gregorian conversion happens once, at the system boundary
- Idempotency keys on every state-mutating operation, recorded before the call
- Error classification separates balance, validation, and network failures
- Periodic reconciliation alerts on drift instead of overwriting it
Conclusion
"Muqeem integration" is not an API project. It is a state reconciliation project across three government systems and yours, under the constraints of a platform that exposes no public interface and meters you per transaction.
The establishments that get this right are not buying a better connector. They treat compliance as a layer they own — understanding the dependencies, preventing duplicates, and surfacing drift instead of hiding it.
If you are managing expatriate workers on spreadsheets, or carrying a Muqeem connector that fails silently, start by mapping where state lives today and where it drifts. The answer is usually smaller than you fear and clearer than you expect.
We review Saudi government platform integrations regularly — Qiwa, Mudad, Muqeem, NPHIES, and ZATCA. If you want an independent read on your current architecture before committing to a vendor or starting a build, get in touch for a diagnostic review of your residency workflow: where the source of truth lives, where it drifts, and what is genuinely worth automating.