The BPJS Ketenagakerjaan API uses HMAC-SHA256 signature authentication. You need a Consumer ID (Cons ID) issued by BPJS, a Secret Key for signing requests, and User Keys for specific service types. The signature is built from a string composed of ConsID, the request timestamp (in Unix epoch seconds), and the Secret Key.
The most common cause is server clock drift. BPJS Ketenagakerjaan's HMAC authentication requires the request timestamp to match their server's clock within a narrow tolerance window — even a few seconds of drift triggers a 401 that looks like a credential failure. Always run NTP time synchronization on your integration server and log the timestamp you send alongside each response code to isolate the issue.
Only if you need the live HMAC-SHA256 bridging API for real-time checks — most payroll systems never reach that tier, since SIPP Online (free, self-service reporting) and EPS (host-to-host payment) already cover monthly reporting and contribution payment. If you do need it, BPJS expects a formal legal entity (PT or CV) as the signing party, a documented use case, a technical contact who can pass security review, and patience: the cycle from request to signed PKS and production credentials commonly takes weeks to months. For client projects, the client's company — not the developer's — is almost always the signing party.
For BPJS Ketenagakerjaan: JKK is 0.24-1.74% of salary (employer, varies by risk class); JKM is 0.30% (employer); JHT is 5.7% total (3.7% employer + 2% employee); JP is 3% total (2% employer + 1% employee, capped at an IDR 11,086,300 salary base as of March 2026 — this cap is adjusted annually under PP No. 45/2015, so store it as a config value); and JKP is 0.46%, funded entirely by the government and recomposed JKK/JKM contributions rather than deducted from pay. For BPJS Kesehatan: 5% of salary (4% employer + 1% employee), with the salary capped at IDR 12 million for premium calculation. These figures must match BPJS's own calculation exactly to avoid reporting rejections.
Third-party aggregator services such as IAK API (api.iak.id) offer BPJS Ketenagakerjaan inquiry as a postpaid product through a PPOB aggregator API, with separate product codes for salaried workers (BPJSTKPU) and informal participants (BPJSTKBPU), eliminating the need for a direct BPJS partnership. Requests are signed with a simple MD5 hash rather than BPJS's own HMAC-SHA256 scheme, which is why this route is popular with payment apps and HR SaaS platforms. The trade-off is a per-transaction fee paid to the aggregator and dependence on the third party's uptime and data accuracy.
Start at the bottom of the ladder: calculate contributions correctly and export a SIPP-compatible file for manual upload — no approval needed. Next, register your company for SIPP Online (sipp.bpjsketenagakerjaan.go.id) to manage worker and wage data directly through the portal instead of manual files. Add EPS (eps.bpjsketenagakerjaan.go.id) for host-to-host payment through a partner bank. Only pursue the live bridging API — which requires a negotiated PKS — if your product genuinely needs real-time balance checks that SIPP and EPS can't provide.
Your facility must already be a BPJS Kesehatan-partnered faskes running its clinic or hospital software for at least one month, with at least one completed staff training session and 30+ active electronic medical records in the past month. Submit a written request to your local BPJS Kesehatan branch office including your Kode Faskes, facility name, a signed Pakta Integritas (integrity pact), and your production web-service URL for IP/domain whitelisting. BPJS issues development credentials first; after a joint UAT with BPJS's regional IT team passes, you receive production Consumer ID, Secret Key, and User Key. Budget several weeks for the full cycle.
Key Takeaway
BPJS integration for Indonesian payroll and ERP systems is not a single public API: most companies calculate contributions and report through the free SIPP Online portal, a live HMAC-SHA256 bridging API requires a formal PKS partnership with BPJS Ketenagakerjaan, and BPJS Kesehatan's VClaim and PCare access is open to any qualifying healthcare facility that applies directly.
If you're building payroll, HR, or ERP systems for Indonesian companies, BPJS integration is eventually unavoidable. BPJS Ketenagakerjaan (employment social security) and BPJS Kesehatan (health insurance) are mandatory for all formal Indonesian employees — which means any payroll system that handles Indonesian employee data needs to calculate BPJS contributions, report them, and ideally submit them programmatically. I put this guide together while researching BPJS integration for a prospective ERP project for a medium-sized law firm in Indonesia — that project hasn't been built yet, so treat this as a research and learning writeup rather than a field report. Even so, the gap between BPJS's official documentation and its real-world API behavior turned out to be wide enough that I wanted to share what I found.
There are two separate BPJS systems: BPJS Ketenagakerjaan (Labor BPJS, formerly Jamsostek) covers work accident insurance (JKK), death insurance (JKM), old age savings (JHT), pension (JP), and job-loss insurance (JKP — Jaminan Kehilangan Pekerjaan, added in 2022). BPJS Kesehatan covers health insurance (JKN). Both have separate APIs, separate credentials, and separate integration requirements. For payroll integration, you primarily need BPJS Ketenagakerjaan's contribution calculation and reporting. For healthcare management systems (klinik, rumah sakit), BPJS Kesehatan's PCare and VClaim APIs are the relevant interfaces.
BPJS Ketenagakerjaan doesn't run a public, self-service developer portal. The api-dev.bpjsketenagakerjaan.go.id subdomain this article originally pointed to has since been repurposed for an internal attendance system — a reminder that BPJS subdomains get reorganized without notice, so verify any BPJS URL before building against it. In practice, most payroll systems reach BPJS Ketenagakerjaan through two official web portals rather than a raw API: SIPP Online (sipp.bpjsketenagakerjaan.go.id) for managing worker, wage, and contribution data — free for any legally registered employer, and increasingly able to accept direct payroll-software sync through company-issued API keys — and EPS (eps.bpjsketenagakerjaan.go.id) for host-to-host contribution payment through partner banks. The live HMAC-SHA256 bridging API (Cons ID, Secret Key, User Key) does exist, but it isn't a self-serve signup; it's negotiated case-by-case with BPJS's IT partnership team, and most teams never need it because SIPP and EPS already cover reporting and payment.
BPJS Kesehatan offers multiple API services: VClaim for eligibility verification and claims management (used by hospitals); PCare for primary care clinic integration (puskesmas, klinik pratama); Antrean for queue management at BPJS-registered healthcare facilities; and Apotek for pharmacy management. Authentication uses basic credentials (username/password, often encoded in base64) plus a signature derived from a shared secret. Integration requires formal partnership with BPJS Kesehatan — you cannot access production APIs without a signed cooperation agreement (PKS — Perjanjian Kerja Sama). Unlike BPJS Ketenagakerjaan, BPJS Kesehatan has an active community-library ecosystem: ssecd/jkn wraps VClaim, PCare, Antrean, Apotek, and i-Care for Node.js, Deno, and Bun, and aamdsam/bridging-bpjs offers a Laravel/PHP equivalent for VClaim and PCare — both are worth evaluating before writing a client from scratch.
Unlike BPJS Ketenagakerjaan, BPJS Kesehatan's bridging process for healthcare facilities is well-documented and largely self-initiated. To apply, your facility (klinik, puskesmas, or rumah sakit) must already be a BPJS Kesehatan-partnered faskes running its clinic or hospital software for at least one month, with at least one completed staff training session and a minimum of 30 active electronic medical records in the past month. You then submit a written request to your local BPJS Kesehatan branch office (Kantor Cabang) asking for a Consumer ID, Secret Key, and User Key at the development tier. The request letter must include your Kode Faskes and facility name, a signed Pakta Integritas (an integrity pact governing Consumer ID use), and your production web-service URL so BPJS can whitelist your IP or domain. Once development is complete, you submit a UAT (User Acceptance Test) request; BPJS's regional IT helpdesk and PMP team run the UAT jointly with your developers, and only after it passes do you receive production credentials. Budget several weeks for the full cycle, and confirm with your branch office whether the request letter needs a physical signature and stamp duty (materai) — most branches still require a paper submission alongside the digital one.
// BPJS Ketenagakerjaan — HMAC-SHA256 Auth (Node.js)
import crypto from "crypto"
function buildBpjsHeaders(consId: string, secret: string) {
const timestamp = Math.floor(Date.now() / 1000).toString()
// Signature string: consId + "&" + timestamp
const sigString = consId + "&" + timestamp
const signature = crypto
.createHmac("sha256", secret)
.update(sigString)
.digest("base64")
return {
"X-cons-id": consId,
"X-timestamp": timestamp,
"X-signature": signature,
"Content-Type":"application/json",
}
}
// Contribution calculation (2026 rates — JP cap effective March 2026)
function calcBpjsContributions(gaji: number) {
const capJP = 11_086_300 // adjusted yearly per PP No. 45/2015, GDP-indexed
const capKes = 12_000_000
return {
jht_employer: gaji * 0.037,
jht_employee: gaji * 0.02,
jp_employer: Math.min(gaji, capJP) * 0.02,
jp_employee: Math.min(gaji, capJP) * 0.01,
jkk: gaji * 0.0024, // risk class 1 (office)
jkm: gaji * 0.003,
jkp: gaji * 0.0046, // JKP — government-funded, not payroll-deducted
kes_employer: Math.min(gaji, capKes) * 0.04,
kes_employee: Math.min(gaji, capKes) * 0.01,
}
}
The BPJS API timestamp format is a common source of integration failures. BPJS Ketenagakerjaan's HMAC authentication requires the request timestamp in a specific format matching their server's clock within a tolerance window. If your server clock drifts by more than a few seconds, all requests will return 401 errors that look like credential problems. Always use NTP time synchronization on your integration server and log the timestamp you're sending alongside the response code when debugging BPJS authentication failures.
Before you can integrate with BPJS APIs, you need to correctly calculate contributions. As of March 2026, the contribution rates for BPJS Ketenagakerjaan are: JKK (Jaminan Kecelakaan Kerja): 0.24%–1.74% of salary (employer, rate depends on risk class); JKM (Jaminan Kematian): 0.30% of salary (employer); JHT (Jaminan Hari Tua): 5.7% of salary total (3.7% employer + 2% employee); JP (Jaminan Pensiun): 3% of salary total (2% employer + 1% employee), capped at an IDR 11,086,300 wage base — a figure BPJS adjusts annually based on Indonesia's GDP growth under PP No. 45/2015, so store it as a configurable value, not a hardcoded constant; JKP (Jaminan Kehilangan Pekerjaan): 0.46% of salary, funded entirely by the central government and recomposed JKK/JKM contributions — it is never deducted from employer or employee pay, so leave it out of net-salary calculations even though it appears on the BPJS reporting file. For BPJS Kesehatan: 5% of salary (4% employer + 1% employee, salary capped at IDR 12 million for premium calculation, unchanged since the last adjustment). These calculations are straightforward to implement but must match BPJS's own calculation exactly — discrepancies will cause reporting rejections.
Rather than one integration pattern, think of BPJS Ketenagakerjaan access as a ladder — pick the lowest rung that satisfies your requirement, since each rung up costs more approval time. Rung 1: calculate contributions correctly in your payroll engine and export a SIPP-compatible file for manual upload — zero approval needed, works for any company today. Rung 2: register for SIPP Online directly and manage worker and wage mutations, plus contribution submissions, through the portal instead of manual file handling — free, self-service, available to any registered employer. Rung 3: connect EPS to a partner bank for host-to-host contribution payment, removing the manual bank-transfer step. Rung 4: use a PPOB aggregator such as IAK API for on-demand BPJS Ketenagakerjaan inquiry or payment without a direct BPJS relationship — a per-transaction fee, but live. Rung 5: negotiate a formal PKS for the live HMAC-SHA256 bridging API — real-time balance checks and full programmatic control, but only justified at meaningful scale, since the approval process takes weeks to months. Most HR and payroll products for the Indonesian market never go past rung 3.
# BPJS Integration Patterns (beyond batch reporting via SIPP Online)
## Pattern 2: Real-time JHT Balance Check (negotiated bridging API)
GET https://<cons-id-issued-endpoint>/saldo/...
Headers: X-cons-id, X-timestamp, X-signature
Response: { "kpj": "...", "saldo": 12500000, "status": "active" }
# Endpoint issued per-company after PKS approval — not publicly documented
## Pattern 3: PPOB Aggregator (no PKS required)
POST https://api.iak.id/api/v1/bill/check
Body: {
"commands": "inq-pasca",
"username": "your_registered_phone_number",
"code": "BPJSTKPU", // Penerima Upah (salaried); BPJSTKBPU for informal workers
"hp": "KPJ_or_bill_number",
"ref_id": "unique_ref_id",
"sign": "md5(username + api_key + ref_id)"
}
# Charges per-transaction fee (~IDR 2,500–5,000)
# No direct BPJS partnership needed — separate inquiry + payment calls
Here's the authentication pattern for BPJS Ketenagakerjaan API in Node.js. The signature is generated using HMAC-SHA256 over a string composed of ConsID:timestamp:Secret. The timestamp must be in seconds since Unix epoch (not milliseconds). Request headers require X-cons-id, X-timestamp, X-signature, and the Content-Type. A critical gotcha: the BPJS staging environment sometimes returns different error codes than production — always test the exact production credentials in staging before considering integration complete. Treat this as the rung 5 tier described above — confirm you've actually exhausted SIPP Online, EPS, and aggregator options before investing in this level of integration.
If you actually need rung 5 — the live bridging API — budget for a real approval process, not a signup form. BPJS Ketenagakerjaan will expect: a formal legal entity (PT or CV, not an individual or freelance contract) as the signing party; a documented use case that justifies real-time access, since batch reporting via SIPP already covers most needs; a technical point of contact who can pass BPJS's security and integration review; and patience — the cycle from initial request to a signed PKS and production credentials commonly takes weeks to months, and BPJS controls the timeline, not you. If you're building for a client rather than your own company, the client's legal entity — not your development shop — is almost always the party that must sign, so confirm this before quoting a delivery date. It's worth explicitly asking BPJS's partnership team whether your use case even requires the live API, since SIPP Online, EPS, or a PPOB aggregator often satisfy the actual business requirement at a fraction of the approval cost.
For projects where direct BPJS API integration is too complex or the PKS timeline is too long, third-party BPJS integration services exist in Indonesia. IAK API (api.iak.id) offers BPJS Ketenagakerjaan inquiry as a postpaid product through their PPOB (payment point online bank) aggregator API, with separate product codes for salaried workers (BPJSTKPU) and informal, self-employed participants (BPJSTKBPU). Requests are signed with an MD5 hash of your username, API key, and reference ID rather than BPJS's own HMAC-SHA256 scheme — a much lower integration bar, which is why PPOB aggregators are popular with HR SaaS platforms. The tradeoff: you pay a per-transaction fee to the aggregator, and you're dependent on a third party's uptime and data accuracy.
BPJS regulations and API specifications change — contribution rates have been updated multiple times in the past five years, and API endpoints have migrated. Build your BPJS integration with change in mind: put all contribution rates in a database table or config file (not hardcoded constants); implement version-aware API clients that can be updated without rewriting business logic; log all API requests and responses for debugging; and implement automated tests that validate contribution calculations against known-correct examples. When BPJS changes rates (usually announced in government regulation — Peraturan Pemerintah), you should be able to update your system in one place with confidence.
Key terms: BPJS Ketenagakerjaan, BPJS Kesehatan, JHT, JP, JKK, JKM, JKP, PKS, SIPP Online, EPS, HMAC-SHA256, PCare, VClaim
JHTJPJKPPKSSIPP OnlineHMAC-SHA256