Repository navigation
Onboarding
This guide walks you through setting up your development environment, obtaining SATUSEHAT credentials, and sending your first API request.
- SATUSEHAT Developer Account — register at https://developer.satusehat.kemkes.go.id
- PHP 7.4+ or PHP 8.x installed
- Composer installed
- Internet access to reach SATUSEHAT APIs
- Go to https://developer.satusehat.kemkes.go.id
- Create an account / log in
- Navigate to Integration → New Application
- Create a new application with a name (e.g. "My FHIR App")
- You will receive:
- Client ID
- Client Secret
- For each environment (DEV / STG / PROD), register your application separately
For non-production environments, SATUSEHAT provides sandbox organization IDs.
DEV Environment comes pre-seeded with test organization IDs. You can use the provided dev practitioner and patient IDs directly.
For STG and PROD, register your actual organization in the SATUSEHAT portal and obtain the official organization_id.
composer require ivanwilliammd/satusehat-integrationCreate a .env file in your project root:
# Choose environment: DEV | STG | PROD
SATUSEHAT_ENV=DEV
# DEV environment credentials
SATUSEHAT_BASE_URL_DEV=https://api-satusehat-dev.dto.kemkes.go.id
CLIENTID_DEV=your_client_id_from_portal
CLIENTSECRET_DEV=your_client_secret_from_portal
ORGID_DEV=your_organization_id
# STG environment credentials
SATUSEHAT_BASE_URL_STG=https://api-satusehat-stg.dto.kemkes.go.id
CLIENTID_STG=your_client_id_from_portal
CLIENTSECRET_STG=your_client_secret_from_portal
ORGID_STG=your_organization_id
# PROD environment credentials
SATUSEHAT_BASE_URL_PROD=https://api-satusehat.kemkes.go.id
CLIENTID_PROD=your_client_id_from_portal
CLIENTSECRET_PROD=your_client_secret_from_portal
ORGID_PROD=your_organization_idIf using Laravel:
php artisan migrateFor standalone PHP, create the required tables (see Installation page).
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Satusehat\Integration\SSRequest\SSRequest;
use Satusehat\Integration\OAuth2Client;
use Satusehat\Integration\DataType\Identifier;
use Satusehat\Integration\DataType\HumanName;
use Satusehat\Integration\DataType\Address;
use Satusehat\Integration\DataType\ContactPoint;
use Satusehat\Integration\Builder\PayloadBuilderPatient;
// Initialize
$ss = new SSRequest(new OAuth2Client());
// Build a Patient resource
$patient = (new PayloadBuilderPatient)
->addIdentifier(new Identifier(
system: 'https://fhir.kemkes.go.id/id/NIK',
value: '3312345678901234'
))
->addName(new HumanName(
family: 'Doe',
given: ['John', 'Michael'],
use: 'official'
))
->addTelecom(new ContactPoint(
system: 'phone',
value: '081234567890',
use: 'mobile'
))
->addAddress(new Address(
use: 'home',
line: ['Jl. Sudirman No.1'],
city: 'Jakarta Selatan',
district: 'Kebayoran Baru',
state: 'DKI Jakarta',
postalCode: '12190',
country: 'ID'
))
->setGender('male')
->setBirthDate('1990-01-15')
->setActive(true)
->build();
// Send to SATUSEHAT
$resp = $ss->post('Patient', $patient);
if ($resp->isSuccess()) {
echo "SUCCESS! Patient ID: " . $resp->getResourceId() . "\n";
} else {
echo "FAILED:\n";
foreach ($resp->getErrorMessages() as $msg) {
echo " - $msg\n";
}
}// Search by NIK
$resp = $ss->get('Patient', [
'identifier' => 'https://fhir.kemkes.go.id/id/NIK|3312345678901234'
]);
// Search by name
$resp = $ss->get('Patient', [
'name' => 'Doe',
'birthdate' => '1990-01-15'
]);
// Get a specific patient
$resp = $ss->get('Patient/12345678-1234-1234-1234-123456789012');| Environment | Purpose | Base URL |
|---|---|---|
| DEV | Development & testing | https://api-satusehat-dev.dto.kemkes.go.id |
| STG | Staging / pre-production | https://api-satusehat-stg.dto.kemkes.go.id |
| PROD | Production | https://api-satusehat.kemkes.go.id |
- DEV — Faster validation, test data available. Token never truly expires.
- STG — Near-production behavior, real validation rules enforced.
- PROD — Full validation, real patient data. Rate limits apply strictly.
Simply change SATUSEHAT_ENV in your .env and update the corresponding credentials:
// Or override at runtime:
$oauth2 = new OAuth2Client();
$oauth2->satusehat_env = 'STG';
$oauth2->base_url = 'https://api-satusehat-stg.dto.kemkes.go.id';
$oauth2->fhir_url = 'https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1';
$oauth2->client_id = 'your_stg_client_id';
$oauth2->client_secret = 'your_stg_client_secret';
$oauth2->organization_id = 'your_stg_org_id';| System | Use Case |
|---|---|
https://fhir.kemkes.go.id/id/NIK |
Indonesian National ID (NIK/KTP) |
https://fhir.kemkes.go.id/id/KTP |
KTP identifier |
http://terminology.hl7.org/CodeSystem/v3-ActCode |
Encounter class codes |
http://terminology.hl7.org/CodeSystem/condition-clinical |
Condition clinical status |
http://hl7.org/fhir/sid/icd-10 |
ICD-10 diagnosis codes |
http://sys-ids.kemkes.go.id/kfa |
KFA drug codes |
http://loinc.org |
LOINC observation codes |
http://snomed.info/sct |
SNOMED CT terminology |
http://unitsofmeasure.org |
UCUM units of measure |
http://www.whocc.no/atc |
ATC drug classification |
DEV environment provides pre-seeded test practitioner and patient IDs. Check OAuth2Client:
$oauth2 = new OAuth2Client();
print_r($oauth2->practitioner_dev); // Array of test practitioner IDs
print_r($oauth2->patient_dev); // Array of test patient IDs$ss = new SSRequest($oauth2, config: [
'log_enabled' => true,
]);The library handles 429 automatically. For high-volume scenarios, use the queue worker:
use Satusehat\Integration\Queue\SqliteQueue;
use Satusehat\Integration\Queue\Worker;
use Satusehat\Integration\Queue\RateLimiter;
$queue = new SqliteQueue(new PDO('sqlite:' . __DIR__ . '/queue.db'));
$worker = new Worker($queue, [...], new RateLimiter(300)); // 300 RPM
$worker->process(100);- Read the full Usage guide
- Explore all PayloadBuilder classes
- Understand FHIR-DataTypes
- Review Error-Handling patterns