writing/blog/2026/08
BlogAug 12, 2026·6 min read

Maroof + Wathq: Verify Saudi Business Registration via API

How to build Saudi merchant verification into your platform using the Wathq CR API and Maroof status checks. Full TypeScript integration guide with error handling.

When you build a marketplace, payment gateway, or B2B procurement platform in Saudi Arabia, you face a regulatory obligation most documentation ignores: you must verify that each merchant holds a valid commercial registration (سجل تجاري) and — for e-commerce operations — is authenticated on منصة الأعمال (formerly معروف / Maroof). The Maroof badge signals to Saudi consumers that a store is licensed, and payment processors increasingly require it before onboarding sellers.

The problem is that Saudi Arabia's official verification is split across two systems:

  1. Commercial Registration (السجل التجاري) — managed by the Ministry of Commerce
  2. منصة معروف → منصة الأعمال — the e-commerce authentication layer (migrated March 2023)

Neither system exposes a public REST API directly. The programmatic route goes through واثق (Wathq) — Saudi Arabia's official business data API gateway at developer.wathq.sa.

This guide shows you how to integrate Wathq to build a real-time business verification flow in TypeScript.


What Is Maroof, and What Changed in 2023?

Maroof (معروف) launched as the Ministry of Commerce's platform to certify Saudi online stores. Any store displaying the Maroof badge had a valid commercial registration and was licensed for e-commerce activity.

In March 2023, the Ministry migrated e-store authentication to منصة الأعمال (business.sa), the Saudi Business Center's unified business platform. The Maroof badge still appears on existing certified storefronts, but new registrations and renewals now flow through business.sa. For consumers, nothing visible changed. For developers building verification into a platform, the path is now:

CR number → Wathq API → active status + e-commerce activity confirmed


The Wathq API: Saudi Arabia's Business Data Gateway

Wathq is operated under the SDAIA ecosystem and acts as the single authenticated gateway to multiple Saudi government data sources. The Commercial Registration API — version 6.7.0 at time of writing — is the relevant service for merchant verification.

Getting access:

  1. Create an account at developer.wathq.sa
  2. Subscribe to the Commercial Registration API (a sandbox environment is available)
  3. Obtain your Bearer token credentials
  4. Graduate to the production endpoint after sandbox testing

Core endpoints:

EndpointPurpose
GET /info/{id}Basic CR data: name, status, activity type, dates
GET /fullinfo/{id}Complete CR data including owners, capital, branches
GET /owners/{id}Owner and partner shareholding details
GET /related/{id}/{idType}All registrations linked to a national or entity ID

The id parameter accepts:

  • A 10-digit CR number (format: 10xxxxxxxx)
  • A 10-digit national unified number (format: 700xxxxxxx) — required for active and pending records

TypeScript Integration

Basic CR verification

const WATHQ_BASE = process.env.WATHQ_BASE_URL!;
const WATHQ_TOKEN = process.env.WATHQ_API_TOKEN!;
 
interface CRInfo {
  crNumber: string;
  crName: string;
  status: string; // 'Active' | 'Expired' | 'Cancelled'
  activities: string[];
  issuanceDate: string;
  expiryDate: string;
}
 
async function verifyCR(id: string, lang: 'ar' | 'en' = 'ar'): Promise<CRInfo> {
  const res = await fetch(`${WATHQ_BASE}/info/${id}?language=${lang}`, {
    headers: {
      Authorization: `Bearer ${WATHQ_TOKEN}`,
      'Content-Type': 'application/json',
    },
  });
 
  if (res.status === 404) throw new Error('CR_NOT_FOUND');
  if (res.status === 401) throw new Error('WATHQ_AUTH_FAILED');
  if (res.status === 429) throw new Error('WATHQ_QUOTA_EXCEEDED');
  if (!res.ok) throw new Error(`WATHQ_ERROR_${res.status}`);
 
  return res.json();
}

Full merchant onboarding check

interface OnboardingResult {
  valid: boolean;
  crStatus: string;
  errorCode?: string;
}
 
async function onboardSaudiMerchant(
  crNumber: string,
  nationalId: string
): Promise<OnboardingResult> {
  // Step 1: Verify CR is active
  const info = await verifyCR(crNumber);
  if (info.status !== 'Active') {
    return { valid: false, crStatus: info.status, errorCode: 'CR_NOT_ACTIVE' };
  }
 
  // Step 2: Confirm e-commerce activity is present
  const hasEcommerceActivity = info.activities.some(
    (a) =>
      a.includes('تجارة إلكترونية') ||
      a.toLowerCase().includes('electronic commerce')
  );
  if (!hasEcommerceActivity) {
    return { valid: false, crStatus: info.status, errorCode: 'NO_ECOMMERCE_ACTIVITY' };
  }
 
  // Step 3: Verify declared owner matches the CR
  const ownersRes = await fetch(
    `${WATHQ_BASE}/owners/${crNumber}?language=ar`,
    { headers: { Authorization: `Bearer ${WATHQ_TOKEN}` } }
  );
  const ownersData = await ownersRes.json();
  const ownerMatch = ownersData.owners?.some(
    (o: { nationalId: string }) => o.nationalId === nationalId
  );
 
  if (!ownerMatch) {
    return { valid: false, crStatus: info.status, errorCode: 'OWNER_MISMATCH' };
  }
 
  return { valid: true, crStatus: info.status };
}

Four Failure Modes to Handle

1. The CR 700 rule

Active and pending CR records can only be queried using the 10-digit national unified number starting with 700. Passing an older 10-digit CR number for active records returns error 400.1.5. Collect both identifiers at merchant registration — the CR number and the national unified number.

2. Expired CRs with live Maroof badges

Maroof badges persist on storefronts even after a CR expires. Never trust a visual badge. Query Wathq at every onboarding and schedule a background re-verification every 30 days for active merchants on your platform.

3. Quota exhaustion (429)

Wathq enforces per-plan call quotas. For high-volume seller onboarding, cache Wathq responses in Redis keyed by CR number with a 24-hour TTL. Most CR status changes happen on a monthly cycle; daily re-verification is overkill and will burn your quota.

4. Activity code mismatches

A CR can be active but registered for a physical-only activity — repair services, for example — with no e-commerce classification. Pull GET /fullinfo/{id} during onboarding to read the full activity list and reject CRs that lack an e-commerce or retail activity code.


Displaying Maroof Status on Your Platform

The منصة الأعمال (Maroof replacement) authentication is a step the merchant completes on business.sa — there is no API to check or trigger it programmatically in real time. The pattern used by Saudi payment integrators (HyperPay, Moyasar, STCPay) is:

  1. Collect the merchant's CR number and national unified number
  2. Verify via Wathq that the CR is active with an e-commerce activity
  3. Ask the merchant to upload their منصة الأعمال verification certificate (PDF issued by business.sa)
  4. Display your own "Verified Seller" badge once both checks pass

This replicates what managed certificate services like lahint.sa do — you're internalising that logic and owning the refresh cycle.


This CR Check Rarely Lives Alone

In production Saudi platforms, CR verification is one node in a broader compliance chain. The same merchant will also need:

Together, these form the compliance backbone of any Saudi B2B marketplace or HR platform.


Building Saudi merchant verification and hitting edge cases the docs don't cover? The Noqta team has integrated Wathq, Qiwa, Mudad, and ZATCA for marketplace platforms across the Gulf. Contact us — we can scope your verification layer in a single call.