PHPackages                             banguncode/php-frista - 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. banguncode/php-frista

ActiveLibrary[API Development](/categories/api)

banguncode/php-frista
=====================

A simple PHP library for BPJS Kesehatan facial recognition integration.

v1.1.0(1mo ago)7367MITPHPPHP &gt;=5.5

Since May 26Pushed 1mo agoCompare

[ Source](https://github.com/banguncode/PHP-Frista)[ Packagist](https://packagist.org/packages/banguncode/php-frista)[ RSS](/packages/banguncode-php-frista/feed)WikiDiscussions main Synced today

READMEChangelog (1)DependenciesVersions (2)Used By (0)

PHPFrista
=========

[](#phpfrista)

**PHPFrista** is a PHP library for integrating with **BPJS Kesehatan FRISTA** (Facial Recognition Integrated System).
It covers the full biometric flow: authentication, face verification, and first-time enrollment.

---

Features
--------

[](#features)

- Token-based authentication with server-side session validation — stale tokens are detected and refreshed automatically.
- Face identification from encoding alone, no ID required (`/face/recognition2`).
- Participant lookup by NIK (`/face/nik2`).
- Face verification by ID + encoding (`/face/match2`) with all documented server responses mapped to `StatusCode` constants.
- Biometric enrollment from a JPEG file, base64 string, or encoding array (`/face/upload`, `/face/upload2`).
- Input validation for identity number, encoding format, and image type.
- Single shared cURL wrapper — no duplicated request boilerplate.

---

Important
---------

[](#important)

`navigator.mediaDevices.getUserMedia()` only works on `localhost` or over HTTPS.

For capturing face descriptors in the browser, [face-api.js](https://github.com/justadudewhohacks/face-api.js) works well with the FRISTA encoding format. The `detection.descriptor` array from `withFaceDescriptor()` is a 128-element `Float32Array` that maps directly to the `$encoding` parameter.

Example capture page:

```
>

    Face Capture

        body { font-family: Arial; margin: 20px; }
        #videoWrap { position: relative; width: 640px; }
        video { width: 100%; background: #000; transform: scaleX(-1); }
        canvas { position: absolute; left: 0; top: 0; transform: scaleX(-1); }
        #capturedImage { max-width: 640px; margin-top: 20px; display: none; }
        button { padding: 8px 12px; margin: 10px 5px 0 0; }
        #log { margin-top: 10px; padding: 10px; background: #f5f5f5; font-family: monospace; font-size: 12px; max-height: 300px; overflow: auto; }

    Face Capture

    Capture

        const video        = document.getElementById('video');
        const logEl        = document.getElementById('log');
        const btnCapture   = document.getElementById('btnCapture');
        const capturedImage = document.getElementById('capturedImage');

        function log(msg) { logEl.innerHTML += msg + '\n'; }

        async function init() {
            try {
                log('Loading models...');
                await faceapi.nets.ssdMobilenetv1.loadFromUri('./models/ssd_mobilenetv1');
                await faceapi.nets.faceLandmark68Net.loadFromUri('./models/face_landmark_68');
                await faceapi.nets.faceRecognitionNet.loadFromUri('./models/face_recognition');
                log('Models loaded');

                const stream = await navigator.mediaDevices.getUserMedia({ video: true });
                video.srcObject = stream;
                video.addEventListener('loadedmetadata', () => {
                    log('Camera ready');
                    btnCapture.disabled = false;
                });
            } catch (e) {
                log('Error: ' + e.message);
            }
        }

        async function captureAndDetect() {
            const canvas = document.createElement('canvas');
            canvas.width  = video.videoWidth;
            canvas.height = video.videoHeight;
            const ctx = canvas.getContext('2d');

            // Mirror the frame to match the mirrored video display
            ctx.translate(canvas.width, 0);
            ctx.scale(-1, 1);
            ctx.drawImage(video, 0, 0);

            capturedImage.src = canvas.toDataURL();
            capturedImage.style.display = 'block';

            log('Detecting face...');
            const detection = await faceapi
                .detectSingleFace(canvas)
                .withFaceLandmarks()
                .withFaceDescriptor();

            if (!detection) { log('No face detected'); return; }

            log('Score: ' + detection.detection.score.toFixed(2));
            log('Encoding: ' + JSON.stringify(Array.from(detection.descriptor)));
        }

        btnCapture.onclick = captureAndDetect;
        window.addEventListener('load', init);

```

---

Installation
------------

[](#installation)

```
composer require banguncode/php-frista
```

Requirements
------------

[](#requirements)

- PHP &gt;= 5.5
- Extensions: `curl`, `fileinfo`
- Outbound HTTPS access to `frista.bpjs-kesehatan.go.id`

Directory Structure
-------------------

[](#directory-structure)

```
php-frista/
├── src/
│   ├── FacialRecognition.php
│   └── StatusCode.php
├── tests/
│   └── FacialRecognitionTest.php
├── composer.json
└── README.md

```

---

Usage
-----

[](#usage)

### 1. Authenticate

[](#1-authenticate)

```
