PHPackages                             aghfatehi/laravel-saudi-fda - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. aghfatehi/laravel-saudi-fda

ActiveLibrary[API Development](/categories/api)

aghfatehi/laravel-saudi-fda
===========================

Laravel package for Saudi Food and Drug Authority (SFDA) API integration. SDK for Cosmetics, Drugs, Food &amp; Medical Devices with OAuth2 auto-auth. ربط الهيئة العامة للغذاء والدواء السعودية مع لارافيل - دعم مستحضرات التجميل، الأدوية، المنتجات الغذائية، والأجهزة الطبية

v1.1.0(1mo ago)03↓87.5%MITPHPPHP ^8.1CI passing

Since Jun 6Pushed 1mo agoCompare

[ Source](https://github.com/aghfatehi/laravel-saudi-fda)[ Packagist](https://packagist.org/packages/aghfatehi/laravel-saudi-fda)[ RSS](/packages/aghfatehi-laravel-saudi-fda/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (4)Versions (3)Used By (0)

 [![PHP Version](https://camo.githubusercontent.com/d4fe5599dc4fb02fe432b94f8a25d1b06cfc6fbaad6f0baa6dc87ee043ca3e98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d5e382e312d3838393242462e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d706870)](https://www.php.net/) [![Laravel Version](https://camo.githubusercontent.com/b7659162668560f1d9c9b9f097fe5f0f26b317a9b789c2908148eadc43f15cf5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d397c31307c31317c31327c31332d4646324432302e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d6c61726176656c)](https://laravel.com/) [![SFDA Services](https://camo.githubusercontent.com/2efa8f59c3a61dcb760ec325aae9d030da45f368c1920d635befe457aa3ff17d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f534644412d436f736d65746963735f2532425f44727567735f2532425f466f6f645f2532425f4d65646963616c5f446576696365732d3030413835392e7376673f7374796c653d666f722d7468652d6261646765)](https://sfda.gov.sa/) [![License](https://camo.githubusercontent.com/31e62e0eff03ce9ddfdf69d8476340d4f541990bfb152cb02a0f342965252997/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](LICENSE) [![Tests](https://camo.githubusercontent.com/aa8ae5a937803dca9a2fd899465b437787fba3e0a823cb1b9a72e80b6ed5755e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6167686661746568692f6c61726176656c2d73617564692d6664612f6c61726176656c2e796d6c3f7374796c653d666f722d7468652d6261646765266c6162656c3d5465737473)](https://github.com/aghfatehi/laravel-saudi-fda/actions) [![Packagist](https://camo.githubusercontent.com/c0e6f4613e556874a514240e4437c0f79ef1d48e252ebf45b191e209b24a7710/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6167686661746568692f6c61726176656c2d73617564692d6664612e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/aghfatehi/laravel-saudi-fda) [![Downloads](https://camo.githubusercontent.com/a6b0ae8479cdb4ee4ba9e5320b9478b1f1f33dc75090f5a712066ab8f1e0ed00/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6167686661746568692f6c61726176656c2d73617564692d6664612e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/aghfatehi/laravel-saudi-fda) [![FsoftDev](https://camo.githubusercontent.com/d6dcdc51ab1d6a32843c2936f8b0b38bdc58aba5634c2ef96e451791ca293210/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46736f66744465762d46736f66744465762e636f6d2d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://fsoftdev.com) [![Author](https://camo.githubusercontent.com/369b3da733224d2abc71724d11cef62b04f53ad2dcd876721f32e0d989da39d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f417574686f722d414c2d2d414748424152492532304661746568692d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://github.com/aghfatehi)

Saudi FDA (SFDA) API Integration for Laravel
============================================

[](#saudi-fda-sfda-api-integration-for-laravel)

### Laravel package for the Saudi Food and Drug Authority public APIs — Cosmetics, Drugs, Food, Medical Devices

[](#laravel-package-for-the-saudi-food-and-drug-authority-public-apis--cosmetics-drugs-food-medical-devices)

#### By [FsoftDev.com](https://fsoftdev.com) — [AL-AGHBARI Fatehi](https://github.com/aghfatehi)

[](#by-fsoftdevcom--al-aghbari-fatehi)

 **SFDA integration for Laravel — automatic OAuth2 authentication, cosmetics &amp; drug &amp; food &amp; medical device APIs**

---

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements &amp; Installation](#requirements--installation)
- [Configuration](#configuration)
- [Quick Start](#quick-start)
- [Usage](#usage)
    - [Authentication](#authentication)
    - [Cosmetics API](#cosmetics-api)
    - [Drugs API](#drugs-api)
    - [Food API](#food-api)
    - [Medical Devices API](#medical-devices-api)
- [API Routes](#api-routes)
- [Error Handling](#error-handling)
- [Events](#events)
- [Artisan Commands](#artisan-commands)
- [Testing](#testing)
- [Postman Collection](#postman-collection)
- [License](#license)

---

> **Important:** The SFDA API restricts access to Saudi IP addresses only. If your server is outside Saudi Arabia, you must contact SFDA support to add your server IP to their allowed list, or use a Saudi-based server/VPN. Without this, all connection attempts will time out on port 9002.

Requirements &amp; Installation
-------------------------------

[](#requirements--installation)

RequirementVersion**PHP**`^8.1`**Laravel**`9.x` · `10.x` · `11.x` · `12.x` · `13.x`**Extensions**`json`, `curl````
composer require aghfatehi/laravel-saudi-fda
```

Auto-discovery is enabled — no manual service provider registration needed.

Publish the configuration (optional):

```
php artisan vendor:publish --tag=saudi-fda-config
```

---

Configuration
-------------

[](#configuration)

Add to your `.env` file:

```
SFDA_CONSUMER_KEY=your_consumer_key
SFDA_CONSUMER_SECRET=your_consumer_secret
SFDA_ENVIRONMENT=sandbox
```

### All Configuration Options

[](#all-configuration-options)

VariableDefaultRequiredDescription`SFDA_CONSUMER_KEY`—YesYour SFDA Consumer Key`SFDA_CONSUMER_SECRET`—YesYour SFDA Consumer Secret`SFDA_ENVIRONMENT``sandbox`No`sandbox` or `production``SFDA_TOKEN_CACHE_ENABLED``true`NoCache the OAuth2 access token`SFDA_TOKEN_CACHE_STORE``file`NoCache driver (file, redis, memcached, etc.)`SFDA_TOKEN_CACHE_KEY``sfda_access_token`NoCustom cache key for the token`SFDA_API_TIMEOUT``60`NoHTTP request timeout in seconds`SFDA_ROUTES_ENABLED``true`NoEnable/disable built-in API routes`SFDA_ROUTES_PREFIX``api/saudi-fda`NoURI prefix for built-in routes`SFDA_LOGGING_ENABLED``true`NoEnable API call logging`SFDA_LOG_LEVEL``info`NoLog level (debug, info, notice, warning, error)`SFDA_LOG_DATABASE_ENABLED``false`NoLog API requests to `sfda_api_logs` table`SFDA_LOG_DATABASE_CONNECTION`—NoDatabase connection for logging (defaults to your default DB)### Override Base URLs (optional)

[](#override-base-urls-optional)

Each service base URL can be overridden individually:

VariableDefault`SFDA_OAUTH_BASE``https://apis.sfda.gov.sa:9002/v2/oauth``SFDA_COSMETICS_BASE``https://apis.sfda.gov.sa:9002/v2/cosmetics``SFDA_DRUGS_BASE``https://apis.sfda.gov.sa:9002/v2/DMS``SFDA_FOOD_BASE``https://apis.sfda.gov.sa:9002/v2/Food``SFDA_MEDICAL_DEVICES_BASE``https://apis.sfda.gov.sa:9002/v2/dwh-md`---

Quick Start
-----------

[](#quick-start)

```
# Full health check — config + authentication + API connectivity
php artisan saudi-fda:check

# View configuration (credentials masked)
php artisan saudi-fda:check --config
```

### Using the Facade

[](#using-the-facade)

```
use Aghfatehi\SaudiFda\Facades\SaudiFda;

SaudiFda::isConfigured();   // bool — credentials present in config
SaudiFda::isReady();        // bool — credentials valid, token obtained
SaudiFda::environment();    // \Aghfatehi\SaudiFda\Enums\Environment
```

### Dependency Injection

[](#dependency-injection)

```
use Aghfatehi\SaudiFda\SaudiFdaClient;

class ProductController extends Controller
{
    public function __construct(private SaudiFdaClient $sfda) {}

    public function show($barcode)
    {
        return $this->sfda->cosmetics()->getByBarcode($barcode);
    }
}
```

---

### Token Storage &amp; Cache

[](#token-storage--cache)

The access token is automatically cached using Laravel's cache system to avoid requesting a new token on every API call.

**How it works:**

1. On first API call, the package requests an OAuth2 token from SFDA
2. The token (as an `AccessTokenDTO`) is stored in the cache with a TTL of `expiresIn - 300` seconds (5-minute safety margin)
3. Subsequent calls check the cache first — if a valid `AccessTokenDTO` is found, it's reused
4. If a cached token exists but is expired, or if `forceRefresh` is used, a new token is fetched and the cache is updated
5. If any API call receives a **401 Unauthorized**, the package automatically refreshes the token and retries the request once

**Cache configuration via `.env`:**

```
SFDA_TOKEN_CACHE_ENABLED=true        # Enable/disable token caching
SFDA_TOKEN_CACHE_STORE=file          # Cache driver (file, redis, memcached, database)
SFDA_TOKEN_CACHE_KEY=sfda_access_token  # Cache key name
```

**Example — force refresh token:**

```
use Aghfatehi\SaudiFda\Facades\SaudiFda;

// Bypass cache, always get a fresh token
$token = SaudiFda::auth()->getAccessToken(true);

// Token details
$token->accessToken;  // string — the Bearer token
$token->expiresIn;    // int — seconds until expiry (typically 86400)
$token->tokenType;    // string — "Bearer"
```

**Example — clear cached token manually:**

```
use Illuminate\Support\Facades\Cache;

Cache::store(config('saudi-fda.token_cache.store', 'file'))
    ->forget(config('saudi-fda.token_cache.key', 'sfda_access_token'));
```

**Example — use a different cache store (Redis example):**

```
SFDA_TOKEN_CACHE_STORE=redis
```

The package stores a serialized `AccessTokenDTO` object. Any Laravel cache driver that supports serialization works out of the box.

**How auto-refresh works:**

```
Request -> 401 Unauthorized -> Package auto-refreshes token -> Retries request -> Succeeds

```

This happens transparently in `ApiClient` — the method `tokenRefreshCallback` is called when a 401 is detected, and the request is retried once.

---

Usage
-----

[](#usage)

All methods use the `SaudiFda` facade to access the four service groups:

```
use Aghfatehi\SaudiFda\Facades\SaudiFda;

SaudiFda::cosmetics();       // CosmeticsService
SaudiFda::drugs();           // DrugService
SaudiFda::food();            // FoodService
SaudiFda::medicalDevices();  // MedicalDeviceService
```

---

### Authentication

[](#authentication)

The package handles **OAuth2 Client Credentials** automatically — tokens are obtained, cached, and refreshed transparently. If any API call receives a 401 response, the package automatically requests a new token and retries once.

**SFDA Endpoint:** `POST /v2/oauth/accesstoken?grant_type=client_credentials`**Auth:** HTTP Basic (`Consumer Key : Consumer Secret`) **Token Expiry:** 86400 seconds (24 hours)

```
use Aghfatehi\SaudiFda\Facades\SaudiFda;

// Get token (uses cache if available)
$token = SaudiFda::auth()->getAccessToken();
$token->accessToken;  // string — the Bearer token
$token->expiresIn;    // int — seconds until expiry

// Force a fresh token (bypass cache)
$token = SaudiFda::auth()->getAccessToken(true);

// Check credentials validity
SaudiFda::auth()->validateCredentials(); // bool
```

---

### Cosmetics API

[](#cosmetics-api)

**Base URL:** `https://apis.sfda.gov.sa:9002/v2/cosmetics`

#### 1. `list(array $options = [])`

[](#1-listarray-options--)

Paginated list of cosmetic products.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page`Keyword`stringNo—Filter by keyword```
SaudiFda::cosmetics()->list(['page' => 1, 'limit' => 50]);
SaudiFda::cosmetics()->list(['Keyword' => 'cream']);
SaudiFda::cosmetics()->list(['page' => 2, 'limit' => 20, 'Keyword' => 'lotion']);
```

**SFDA Endpoint:** `GET /v2/cosmetics/list?page=&limit=&Keyword=`

---

#### 2. `getById(int $productId)`

[](#2-getbyidint-productid)

Get a single cosmetic product by its SFDA product ID.

ParameterTypeRequiredDefaultDescription`productId`intYes—SFDA product identifier```
SaudiFda::cosmetics()->getById(1495);
```

**SFDA Endpoint:** `GET /v2/cosmetics/Product_Id/{productID}`

---

#### 3. `getByCosmeticNumber(string $cosmeticNumber)`

[](#3-getbycosmeticnumberstring-cosmeticnumber)

Get a cosmetic product by its registration number.

ParameterTypeRequiredDefaultDescription`cosmeticNumber`stringYes—Cosmetic registration number (e.g., `CN-2023-08203`)```
SaudiFda::cosmetics()->getByCosmeticNumber('CN-2023-08203');
```

**SFDA Endpoint:** `GET /v2/cosmetics/cosmeticNumber/{cosmeticNumber}`

---

#### 4. `getByBarcode(string $barcode)`

[](#4-getbybarcodestring-barcode)

Get a cosmetic product by its barcode (EAN/UPC).

ParameterTypeRequiredDefaultDescription`barcode`stringYes—Product barcode```
SaudiFda::cosmetics()->getByBarcode('6281007990215');
```

**SFDA Endpoint:** `GET /v2/cosmetics/BarCode/{barcode}`

---

#### 5. `search(array $options = [])`

[](#5-searcharray-options--)

Advanced search across multiple cosmetic product fields. All parameters are optional — filtered results include only the fields you supply.

ParameterTypeRequiredDefaultDescription`SpecificNameAr`stringNo—Arabic specific name`SpecificName`stringNo—English specific name`BrandName`stringNo—Brand name`barCode`stringNo—Barcode`CosmeticNumber`stringNo—Cosmetic registration number`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::cosmetics()->search(['BrandName' => 'AVON', 'page' => 1]);
SaudiFda::cosmetics()->search(['SpecificNameAr' => 'كريم', 'limit' => 10]);
SaudiFda::cosmetics()->search(['barCode' => '6281007990215']);
```

**SFDA Endpoint:** `GET /v2/cosmetics/search`

---

#### 6. `searchByKeyword(string $keyword, int $page = 1)`

[](#6-searchbykeywordstring-keyword-int-page--1)

Search cosmetic products by a free-text keyword with pagination.

ParameterTypeRequiredDefaultDescription`keyword`stringYes—Search term (goes in URL path)`page`intNo1Page number```
SaudiFda::cosmetics()->searchByKeyword('AVON', 1);
SaudiFda::cosmetics()->searchByKeyword('cream', 2);
```

**SFDA Endpoint:** `GET /v2/cosmetics/search/{keyword}/{page}`

---

#### 7. `getImage(string $imageCode)`

[](#7-getimagestring-imagecode)

Get product image data.

ParameterTypeRequiredDefaultDescription`imageCode`stringYes—Image name/code```
SaudiFda::cosmetics()->getImage('IMG-2023-12345');
```

**SFDA Endpoint:** `GET /v2/cosmetics/image/{image_code}`

---

### Drugs API

[](#drugs-api)

**Base URL:** `https://apis.sfda.gov.sa:9002/v2/DMS`

#### 1. `list(array $options = [])`

[](#1-listarray-options---1)

Paginated list of registered drug products in the Saudi market.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::drugs()->list(['page' => 1, 'limit' => 100]);
SaudiFda::drugs()->list(['page' => 5]);
```

**SFDA Endpoint:** `GET /v2/DMS/drug/list?page=&limit=`

**Sample Response:**

```
{
    "data": [
        {
            "registerNumber": "21-37-10",
            "tradeName": "ORELOX 100MG TABLETS",
            "scientificName": "CEFPODOXIME",
            "atcCode1": "J01DD14",
            "strength": "100",
            "price": "30.80",
            "pharmaceuticalForm": { "nameEn": "Tablet" },
            "marketingStatus": { "nameEn": "Marketed" },
            "legalStatus": { "nameEn": "Prescription" },
            "company": { "nameEn": "SANOFI WINTHROP INDUSTRIE" }
        }
    ],
    "currentPage": 1,
    "pageCount": 791,
    "pageSize": 15,
    "rowCount": 11856
}
```

---

### Food API

[](#food-api)

**Base URL:** `https://apis.sfda.gov.sa:9002/v2/Food`

#### 1. `list(array $options = [])`

[](#1-listarray-options---2)

Paginated list of food products.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::food()->list(['page' => 1, 'limit' => 50]);
```

**SFDA Endpoint:** `GET /v2/Food/product/list/{page}?limit=`

---

#### 2. `getById(int $productId)`

[](#2-getbyidint-productid-1)

Get a food product by its SFDA ID.

ParameterTypeRequiredDefaultDescription`productId`intYes—SFDA product identifier```
SaudiFda::food()->getById(1449070);
```

**SFDA Endpoint:** `GET /v2/Food/product/id/{id}`

---

#### 3. `getByReferenceNumber(string $referenceNumber)`

[](#3-getbyreferencenumberstring-referencenumber)

Get a food product by its reference number.

ParameterTypeRequiredDefaultDescription`referenceNumber`stringYes—Reference number (e.g., `P-3-N-200621-107719`)```
SaudiFda::food()->getByReferenceNumber('P-3-N-200621-107719');
```

**SFDA Endpoint:** `GET /v2/Food/product/referencenumber/{referenceNumber}`

---

#### 4. `getByBarcode(string $barcode)`

[](#4-getbybarcodestring-barcode-1)

Get a food product by its barcode.

ParameterTypeRequiredDefaultDescription`barcode`stringYes—Product barcode```
SaudiFda::food()->getByBarcode('50254156');
```

**SFDA Endpoint:** `GET /v2/Food/product/barcode/{barcode}`

---

#### 5. `search(array $options = [])`

[](#5-searcharray-options---1)

Search food products by keyword.

ParameterTypeRequiredDefaultDescription`keyword`stringYes—Search term`page`intNo1Page number```
SaudiFda::food()->search(['keyword' => 'chocolate', 'page' => 1]);
SaudiFda::food()->search(['keyword' => 'milk', 'page' => 2]);
```

**SFDA Endpoint:** `GET /v2/Food/product/search/{keyword}/{page}`

---

#### 6. `getImage(string $imageCode)`

[](#6-getimagestring-imagecode)

Get food product image data.

ParameterTypeRequiredDefaultDescription`imageCode`stringYes—Image name/code```
SaudiFda::food()->getImage('FOOD-IMG-12345');
```

**SFDA Endpoint:** `GET /v2/Food/image/{image_code}`

---

### Medical Devices API

[](#medical-devices-api)

**Base URL:** `https://apis.sfda.gov.sa:9002/v2/dwh-md`

The Medical Devices API is split into three categories.

#### Low Risk Devices

[](#low-risk-devices)

##### `listLowRisk(array $options = [])`

[](#listlowriskarray-options--)

Paginated list of low-risk medical devices.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::medicalDevices()->listLowRisk(['page' => 1]);
SaudiFda::medicalDevices()->listLowRisk(['page' => 2, 'limit' => 10]);
```

**SFDA Endpoint:** `GET /v2/dwh-md/Lowrisk/list/{page}?limit=`

---

##### `getLowRiskProduct(?int $lowRiskId = null, ?int $productId = null, ?string $accountNumber = null, ?string $registrationNumber = null, ?string $crNumber = null)`

[](#getlowriskproductint-lowriskid--null-int-productid--null-string-accountnumber--null-string-registrationnumber--null-string-crnumber--null)

Get a low-risk device by any combination of identifiers. At least one parameter should be provided.

ParameterTypeRequiredDefaultDescription`lowRiskId`intNonullLow Risk ID`productId`intNonullProduct ID`accountNumber`stringNonullAccount number`registrationNumber`stringNonullRegistration/license number`crNumber`stringNonullCommercial Registration (CR) number```
SaudiFda::medicalDevices()->getLowRiskProduct(lowRiskId: 123);
SaudiFda::medicalDevices()->getLowRiskProduct(registrationNumber: 'LIC-123');
SaudiFda::medicalDevices()->getLowRiskProduct(crNumber: 'CR-456');
```

**SFDA Endpoint:** `GET /v2/dwh-md/Lowrisk/Product?LowRiskID=&productID=&AccountNumber=&RegistrationNumber=&CrNumber=`

---

##### `searchLowRisk(string $keyword, int $page = 1)`

[](#searchlowriskstring-keyword-int-page--1)

Search low-risk devices by keyword.

ParameterTypeRequiredDefaultDescription`keyword`stringYes—Search term`page`intNo1Page number```
SaudiFda::medicalDevices()->searchLowRisk('face mask', 1);
```

**SFDA Endpoint:** `GET /v2/dwh-md/Lowrisk/search/{keyword}/{page}`

---

#### GHTF Devices

[](#ghtf-devices)

##### `listGHTF(array $options = [])`

[](#listghtfarray-options--)

Paginated list of GHTF devices.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::medicalDevices()->listGHTF(['page' => 1]);
```

**SFDA Endpoint:** `GET /v2/dwh-md/GHTF/list/{page}?limit=`

---

##### `getGHTFProduct(?int $propertiesId = null, ?int $mdId = null, ?string $referenceNumber = null, ?string $accountNumber = null, ?string $deviceNumber = null, ?string $crNumber = null)`

[](#getghtfproductint-propertiesid--null-int-mdid--null-string-referencenumber--null-string-accountnumber--null-string-devicenumber--null-string-crnumber--null)

Get a GHTF device by any combination of identifiers.

ParameterTypeRequiredDefaultDescription`propertiesId`intNonullProperties ID`mdId`intNonullMD ID`referenceNumber`stringNonullReference number`accountNumber`stringNonullAccount number`deviceNumber`stringNonullDevice/license number`crNumber`stringNonullCommercial Registration number```
SaudiFda::medicalDevices()->getGHTFProduct(propertiesId: 456);
SaudiFda::medicalDevices()->getGHTFProduct(deviceNumber: 'LIC-456');
```

**SFDA Endpoint:** `GET /v2/dwh-md/GHTF/Product?PropertiesId=&MDId=&ReferenceNumber=&AccountNumber=&DeviceNumber=&CrNumber=`

---

##### `getGHTFAccessory(int $propertiesId)`

[](#getghtfaccessoryint-propertiesid)

Get GHTF device accessory details.

ParameterTypeRequiredDefaultDescription`propertiesId`intYes—Properties ID of the accessory```
SaudiFda::medicalDevices()->getGHTFAccessory(11);
```

**SFDA Endpoint:** `GET /v2/dwh-md/GHTF/Accessory/id/{PropertiesId}`

---

##### `searchGHTF(string $keyword, int $page = 1)`

[](#searchghtfstring-keyword-int-page--1)

Search GHTF devices by keyword.

ParameterTypeRequiredDefaultDescription`keyword`stringYes—Search term`page`intNo1Page number```
SaudiFda::medicalDevices()->searchGHTF('hospital bed', 1);
```

**SFDA Endpoint:** `GET /v2/dwh-md/GHTF/search/{keyword}/{page}`

---

#### TFA Devices

[](#tfa-devices)

##### `listTFA(array $options = [])`

[](#listtfaarray-options--)

Paginated list of TFA devices.

ParameterTypeRequiredDefaultDescription`page`intNo1Page number`limit`intNo—Results per page```
SaudiFda::medicalDevices()->listTFA(['page' => 1]);
```

**SFDA Endpoint:** `GET /v2/dwh-md/TFA/list/{page}?limit=`

---

##### `getTFAAccessory(int $propertiesId)`

[](#gettfaaccessoryint-propertiesid)

Get TFA device accessory details.

ParameterTypeRequiredDefaultDescription`propertiesId`intYes—Properties ID of the accessory```
SaudiFda::medicalDevices()->getTFAAccessory(11);
```

**SFDA Endpoint:** `GET /v2/dwh-md/TFA/Accessory/id/{PropertiesId}`

---

##### `searchTFA(string $keyword, int $page = 1)`

[](#searchtfastring-keyword-int-page--1)

Search TFA devices by keyword.

ParameterTypeRequiredDefaultDescription`keyword`stringYes—Search term`page`intNo1Page number```
SaudiFda::medicalDevices()->searchTFA('ultrasound', 1);
```

**SFDA Endpoint:** `GET /v2/dwh-md/TFA/search/{keyword}/{page}`

---

API Routes
----------

[](#api-routes)

The package registers built-in API routes under `/api/saudi-fda` (configurable via `SFDA_ROUTES_PREFIX`). All routes resolve the `SaudiFdaClient` via Laravel's service container.

MethodEndpointDescriptionRoute Name`GET``/api/saudi-fda/status`Package health check`saudi-fda.status``POST``/api/saudi-fda/auth/token`Get OAuth2 access token`saudi-fda.auth.token``GET``/api/saudi-fda/cosmetics`List cosmetics (query: `page`, `limit`, `Keyword`)`saudi-fda.cosmetics.list``GET``/api/saudi-fda/cosmetics/{id}`Get cosmetic by product ID`saudi-fda.cosmetics.by-id``GET``/api/saudi-fda/cosmetics/number/{cosmeticNumber}`Get cosmetic by registration number`saudi-fda.cosmetics.by-number``GET``/api/saudi-fda/cosmetics/barcode/{barcode}`Get cosmetic by barcode`saudi-fda.cosmetics.by-barcode``POST``/api/saudi-fda/cosmetics/search`Advanced cosmetics search`saudi-fda.cosmetics.search``GET``/api/saudi-fda/drugs`List drugs (query: `page`, `limit`)`saudi-fda.drugs.list``GET``/api/saudi-fda/food`List food products`saudi-fda.food.list``GET``/api/saudi-fda/food/{id}`Get food by ID`saudi-fda.food.by-id``POST``/api/saudi-fda/food/search`Search food products`saudi-fda.food.search``GET``/api/saudi-fda/medical-devices/low-risk`List Low Risk devices`saudi-fda.medical-devices.low-risk``GET``/api/saudi-fda/medical-devices/ghtf`List GHTF devices`saudi-fda.medical-devices.ghtf``GET``/api/saudi-fda/medical-devices/tfa`List TFA devices`saudi-fda.medical-devices.tfa`To disable routes, set `SFDA_ROUTES_ENABLED=false` in your `.env`.

---

Error Handling
--------------

[](#error-handling)

Every API method throws one of two exception types:

ExceptionWhen`AuthenticationException`Invalid or missing credentials`SaudiFdaException`API error (network, rate limit, 4xx/5xx, timeout)```
use Aghfatehi\SaudiFda\Exceptions\SaudiFdaException;
use Aghfatehi\SaudiFda\Exceptions\AuthenticationException;

try {
    $products = SaudiFda::cosmetics()->list();
} catch (AuthenticationException $e) {
    // Check SFDA_CONSUMER_KEY and SFDA_CONSUMER_SECRET
    report($e);
} catch (SaudiFdaException $e) {
    // Network error, rate limit, or SFDA server error
    report($e);
}
```

---

Database Logging
----------------

[](#database-logging)

Every API request/response can be stored in the `sfda_api_logs` table for auditing, debugging, and analytics.

**Enable database logging in `.env`:**

```
SFDA_LOG_DATABASE_ENABLED=true
SFDA_LOG_DATABASE_CONNECTION=mysql   # optional, defaults to default DB connection
```

**Create the table:**

```
php artisan vendor:publish --tag=saudi-fda-migrations
php artisan migrate
```

**What gets logged:**

ColumnTypeDescription`service`stringAPI service name (`cosmetics`, `drugs`, `food`, `medical_devices`)`endpoint`stringAPI endpoint called`method`stringHTTP method (`GET`)`http_code`intHTTP status code`request_payload`jsonRequest parameters (masked for sensitive data)`response_payload`jsonAPI response data (masked for sensitive data)`error_message`textError message if the request failed`duration_ms`floatRequest duration in milliseconds`ip_address`stringClient IP address`created_at`timestampWhen the request was made**Query logs with Eloquent:**

```
use Aghfatehi\SaudiFda\Models\SaudiFdaApiLog;

// Recent failed requests
$failures = SaudiFdaApiLog::whereNotNull('error_message')
    ->latest()
    ->take(10)
    ->get();

// Slow requests (> 2 seconds)
$slow = SaudiFdaApiLog::where('duration_ms', '>', 2000)
    ->latest()
    ->get();

// Requests by service
$cosmeticsLogs = SaudiFdaApiLog::where('service', 'cosmetics')
    ->whereDate('created_at', today())
    ->get();
```

**Sensitive data masking:** When database logging is enabled, the package automatically masks credentials, tokens, and authorization headers in the logged payloads (e.g., `Ejmb****`).

---

Events
------

[](#events)

EventFired WhenPayload`ApiRequestSucceeded`Any API request succeedsEndpoint + duration`ApiRequestFailed`Any API request failsEndpoint + response data---

Artisan Commands
----------------

[](#artisan-commands)

```
# Full health check — config + authentication + API connectivity
php artisan saudi-fda:check

# Test authentication only
php artisan saudi-fda:check --auth

# View current configuration (credentials masked)
php artisan saudi-fda:check --config
```

---

Testing
-------

[](#testing)

```
vendor/bin/phpunit
```

The package includes PHPUnit tests for:

- Facade resolution
- Singleton service instances
- Configuration checks
- Authentication errors

**CI:** GitHub Actions runs tests across PHP 8.1–8.4 x Laravel 9–13 (26 matrix combinations).

---

Postman Collection
------------------

[](#postman-collection)

The repository includes a complete Postman collection: **[SFDA-API-Postman.json](postman/SFDA-API-Postman.json)**

**Features:**

- All 24 SFDA API endpoints with response examples
- Pre-request script for automatic OAuth2 token acquisition
- Test scripts that validate responses and handle 401 token expiry
- Uses environment variables for credentials (never hardcoded)

**How to use:**

1. Postman -&gt; Import -&gt; Select `SFDA-API-Postman.json`
2. Click **Environment** -&gt; **Add** (or edit an existing environment)
3. Add these **Environment variables**:
    - `SFDA_CONSUMER_KEY` = your consumer key
    - `SFDA_CONSUMER_SECRET` = your consumer secret
4. Make your first request — the token is fetched automatically

---

License
-------

[](#license)

MIT — Created by [AL-AGHBARI Fatehi](https://github.com/aghfatehi) — [FsoftDev.com](https://fsoftdev.com)

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance90

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7c0d20683d29aa61fca6b1f9a47a754b2d3e177750f1e8d66975979f2ae8813f?d=identicon)[aghfatehi](/maintainers/aghfatehi)

---

Tags

cosmetics-apidrugs-apifood-apihealthcare-apilaravellaravel-packagemedical-devices-apioauth2php-sdkproduct-searchsaudi-fdasaudi-fda-apisaudi-food-and-drug-authoritysfdasfda-apiphpcomposerapilaravellaravel-packageoauth2REST APIapi integrationpackagistopen-sourcesaudi-arabiafoodcosmeticsالسعوديةلارافيلدمجالتكاملriyadhsfdasaudi-fdaالهيئة العامة للغذاء والدواءSFDA APIsfda saudi arabiaSFDA integration laravelSFDA cosmetics APISFDA drugs APISFDA food APISFDA medical devices APIsfda api laravel packagelaravel api integrationlaravel sfdalaravel saudi fdadrugsmedical devicesمستحضرات التجميلالأدويةالمنتجات الغذائيةالأجهزة الطبيةالمملكة العربية السعودية

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/aghfatehi-laravel-saudi-fda/health.svg)

```
[![Health](https://phpackages.com/badges/aghfatehi-laravel-saudi-fda/health.svg)](https://phpackages.com/packages/aghfatehi-laravel-saudi-fda)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M246](/packages/laravel-ai)[wayofdev/laravel-symfony-serializer

📦 Laravel wrapper around Symfony Serializer.

2117.7k](/packages/wayofdev-laravel-symfony-serializer)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
