API e-Faktur Sipajak mengotomatiskan siklus faktur pajak dari sistem kamu ke DJP Coretax secara host-to-host: buat, ganti (pengganti), batalkan, dan retur faktur keluaran maupun masukan, termasuk dokumen yang dipersamakan.
| Method | Path | Fungsi |
|---|---|---|
| GET | /v1/ref/country | ISO 3166 country codes (3-letter alpha-3) |
| GET | /v1/ref/unit | Units of measure (DJP "UM.xxxx" codes) |
| GET | /v1/ref/transaction-code | DJP transaction codes (TD.003xx) |
| GET | /v1/ref/goods-services | Goods and services classification codes |
| GET | /v1/ref/additional-info | Additional-information codes used with TD.00307 / TD.00308 |
| POST | /v2/efaktur/create-faktur-pk | Issue a new sales invoice |
| POST | /v2/efaktur/create-faktur-pk-amended | Issue a Pengganti (replacement) of an existing invoice |
| POST | /v2/efaktur/cancel-faktur-pk | Cancel an existing invoice |
| POST | /v2/efaktur/create-retur-faktur-pk | List DJP-prepopulated returns for a period — see note below |
| POST | /v2/efaktur/cancel-retur-faktur-pk | Cancel a previously-issued return |
| POST | /v2/efaktur/create-document-pk | Issue a new equivalent document |
| POST | /v2/efaktur/create-document-pk-amended | Issue a Pengganti |
| POST | /v2/efaktur/cancel-document-pk | Cancel an issued equivalent document |
| POST | /v2/efaktur/create-retur-document-pk | Create a retur on an equivalent document |
| POST | /v2/efaktur/cancel-retur-document-pk | Cancel a previously-issued retur |
| POST | /v2/efaktur/create-faktur-pm | Prepopulate / claim an incoming invoice |
| POST | /v2/efaktur/confirmation-amended-cancel-faktur-pm | Acknowledge a supplier-initiated amend or cancel |
| POST | /v2/efaktur/create-retur-faktur-pm | Create a return on a claimed invoice |
| POST | /v2/efaktur/cancel-retur-faktur-pm | Cancel a previously-issued return |
| POST | /v2/efaktur/create-document-pm | Claim an incoming equivalent document |
| POST | /v2/efaktur/create-document-pm-amended | Acknowledge or issue a Pengganti |
| POST | /v2/efaktur/cancel-document-pm | Cancel a claimed document |
| POST | /v2/efaktur/create-retur-document-pm | Create a retur |
| POST | /v2/efaktur/cancel-retur-document-pm | Cancel a previously-issued retur |
The e-Faktur module covers the full lifecycle of VAT invoices (Faktur Pajak): creation of output and input invoices, replacements (Pengganti), cancellations, returns, and the parallel flow for equivalent documents (Dokumen yang Dipersamakan dengan Faktur Pajak). It is by far the largest module by surface area — twenty-two endpoints across five operational groups — but the groups follow a consistent shape, and the per-endpoint deltas are small once the canonical Faktur Keluaran flow is understood.
All endpoints in this module proxy to DJP's Coretax e-Faktur service. They follow the standard soft-error convention (HTTP 200 with data.status = "0" for business-level failures) rather than the HTTP-400 wrapping used by e-Billing and SPT.
6.1 Endpoint summary
The module exposes five functional groups. Reference endpoints are read-only catalogues; the other four groups are transactional and broadly mirror each other.
| Group | Endpoints | Purpose |
|---|---|---|
| Reference data | 5 | Catalogue lookups: countries, units, transaction codes, goods/services codes, additional-info codes. Read-only GETs used by clients to populate form dropdowns and to validate user input before submission. |
| Pajak Keluaran (PK) | 5 | Output VAT invoices issued by the client to its customers. The canonical flow: create, amend (Pengganti), cancel, retur, cancel retur. |
| Dokumen Keluaran (DK) | 5 | Equivalent documents (Dokumen yang Dipersamakan) on the seller side. Same lifecycle shape as PK, used for transaction types DJP permits an equivalent document for (e.g. import declarations, utility bills). |
| Pajak Masukan (PM) | 4 | Input VAT invoices the client receives from its suppliers. The flow is inverted: rather than creating, the client claims invoices DJP has already received from the supplier (prepopulate) and confirms supplier-initiated amendments and cancellations. |
| Dokumen Masukan | 5 | Equivalent documents the client manually claims as input — for non-faktur sources such as customs documents or retail receipts. |
| Utility | 3 | Two helper endpoints: scan (OCR extraction from PDF/JPEG/PNG uploads) and check-status (refresh DJP-side status of an invoice or equivalent document). |
6.2 Module conventions
Five conventions apply across the entire module. Read this section once; the per-endpoint references that follow assume familiarity with each.
6.2.1 The tanggalFaktur format
Dates in e-Faktur request bodies use DDMMYYYY, eight characters with no separator. This applies to tanggalFaktur on PK and PM, tanggalDokumen on DK and Dokumen Masukan, and any other date field in this module.
"tanggalFaktur": "11052026" // 11 May 2026
"tanggalFaktur": "01122026" // 1 December 2026Response timestamps use a mix of formats depending on endpoint and outcome: YYYY-MM-DD for inline-APPROVED creates, YYYY-MM-DD HH:mm:ss for amends and cancels, and DDMMYYYY when echoed back from check-status. Parse permissively rather than asserting a single shape.
6.2.2 The cekDppLain field — PMK 131/2024
Reflects current PPN rule (Jan 2025+). Sipajak implements the PPN computation prescribed by PMK 131/PMK.03/2024: nominal rate 12% applied to a reduced base (DPP Nilai Lain = 11/12 of the contractual price), giving an effective rate of 11% on the original DPP. On every line item, set cekDppLain=true, dpp=<full price>, dppLain=<dpp × 11/12>, tarifPpn=0.12. Sipajak does not enforce the 11/12 ratio server-side, but every production invoice observed since January 2025 follows it.
"objekFaktur": [
{
"brgJasa": "SERVICES",
"hargaSatuan": 4000000,
"jmlBrgJasa": 1,
"totalHarga": 4000000,
"cekDppLain": true,
"dpp": 4000000,
"dppLain": 3666666.67, // 4 000 000 × 11 / 12
"tarifPpn": 0.12,
"ppn": 440000, // 12% × 3 666 666.67 ≈ 440 000 (= 11% × dpp)
"tarifPpnbm": 0,
"ppnbm": 0
}
]Tax rates are sent as decimal fractions (0.12 for 12%), not percentages (12). The same applies to tarifPpnbm. This matches the Sipajak-wide fractional-rate convention noted in section 3.
6.2.3 Signing
Every transactional e-Faktur endpoint that creates or modifies a document requires a DJP-side signing authorisation. The certificate itself is registered out-of-band — during organisation onboarding the .p12 file is uploaded once via the Organization module and held by DJP.
Per-request signing fields:
| Field | Type | Description |
|---|---|---|
npwpNikPenandatangan | string | NIK of the human signer authorised to sign on behalf of the organisation. Distinct from npwpPenjual (the organisation NPWP). |
userId | string | DJP-side user identifier for the signer. Usually identical to npwpNikPenandatangan. |
tempatPenandatangan | string | City where the document is signed (free-form short string). |
passphrasePenandatangan | string | Plaintext passphrase for the signing certificate. Transmit only over TLS. Never log. Treat as a secret of the same sensitivity as a password. |
Sensitive material. passphrasePenandatangan travels as a plaintext body field. The TLS layer is the only protection. Client implementations MUST NOT log this field, MUST NOT echo it in error messages, and SHOULD store it in a secrets-management tool rather than alongside ordinary configuration.
6.2.4 nomorFaktur is allocated by DJP
On create, clients leave nomorFaktur as an empty string or null. DJP draws atomically from the organisation's NSFP (Nomor Seri Faktur Pajak) pool and returns the assigned 17-digit number in data.result.nomorFaktur. Clients do not allocate from their own NSFP pool — the pool is visible via the Sipajak NSFP-management UI for monitoring, but allocation is server-side at DJP.
On amend, cancel, and check-status, the previously-assigned nomorFaktur is supplied verbatim by the client to identify the target invoice.
6.2.5 Soft errors follow the standard pattern
Unlike e-Billing and SPT — which wrap DJP soft errors as HTTP 400 — e-Faktur follows the standard convention documented in section 3.2: HTTP 200 with data.status = "0" and the diagnostic in data.statusMessage. Branch on the inner status string, not on the outer HTTP code.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"status": "0", // string "0" — failure
"statusMessage": "npwpPembeli tidak ditemukan",
"uuid": "<DJP correlation id>"
}
}6.3 Reference data
Five GET endpoints expose DJP reference catalogues. Their primary use is to populate UI dropdowns and to validate user input against current DJP master data. Each accepts a paged search by keyword; default page size is 25, capped at 100.
6.3.1 Endpoint summary
| Method | Path | Catalogue |
|---|---|---|
| GET | /v1/ref/country | ISO 3166 country codes (3-letter alpha-3) |
| GET | /v1/ref/unit | Units of measure (DJP "UM.xxxx" codes) |
| GET | /v1/ref/transaction-code | DJP transaction codes (TD.003xx) |
| GET | /v1/ref/goods-services | Goods and services classification codes |
| GET | /v1/ref/additional-info | Additional-information codes used with TD.00307 / TD.00308 |
6.3.2 Common query parameters
All five endpoints accept the same pagination and search parameters.
| Parameter | Type | Required | Description |
|---|---|---|---|
keyword | string | No | Free-text search across code and name fields |
page | string (numeric) | No | 1-indexed page number. Default 1. |
limit | string (numeric) | No | Page size. Default 25, maximum 100. |
6.3.3 Example — list countries
GET /v1/ref/country
GET /v1/ref/country?keyword=IDN HTTP/1.1
Host: gateway-integration.sipajak.com
Authorization: Basic <base64-encoded credentials>
npwp: 1234567890123000HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"items": [
{
"code": "IDN",
"name": "INDONESIA"
}
],
"total": 1,
"page": 1,
"limit": 25
}
}The four other reference endpoints follow the same envelope; only the item shape differs. Codes returned by these catalogues are stable identifiers safe to cache client-side. A nightly refresh against DJP is appropriate for most integrations.
6.4 Pajak Keluaran (PK)
Output VAT invoices issued by the client to its customers. The lifecycle is: create, optionally amend (Pengganti) one or more times, optionally cancel. A separately-tracked retur flow exists for processing buyer-initiated returns.
6.4.1 Endpoint summary
| Method | Path | Purpose |
|---|---|---|
| POST | /v2/efaktur/create-faktur-pk | Issue a new sales invoice |
| POST | /v2/efaktur/create-faktur-pk-amended | Issue a Pengganti (replacement) of an existing invoice |
| POST | /v2/efaktur/cancel-faktur-pk | Cancel an existing invoice |
| POST | /v2/efaktur/create-retur-faktur-pk | List DJP-prepopulated returns for a period — see note below |
| POST | /v2/efaktur/cancel-retur-faktur-pk | Cancel a previously-issued return |
Endpoint name is misleading on create-retur-faktur-pk. Despite the verb "create" in the path, /v2/efaktur/create-retur-faktur-pk is a list-fetch operation. The endpoint reads returns that DJP has prepopulated for the period and surfaces them for the client to acknowledge. There is no client-initiated retur-create flow on output invoices — the buyer creates the retur on their side and DJP propagates it to the seller's prepopulated list.
6.4.2 Create — POST /v2/efaktur/create-faktur-pk
POST /v2/efaktur/create-faktur-pk
Issues a new sales invoice. DJP allocates the nomorFaktur server-side from the organisation's NSFP pool. The response carries the assigned number and, when signing completes inline, an APPROVED status; otherwise the status is SIGNING_IN_PROGRESS and clients should follow up with check-status.
Request body — header fields
| Field | Type | Required | Description |
|---|---|---|---|
fgUangMuka | boolean | Yes | true for an advance-payment invoice. Use false in the standard case. |
fgPelunasan | boolean | Yes | true for a final-settlement invoice that closes out a previous advance. Use false in the standard case. |
nomorFaktur | string (nullable) | Yes | Leave empty or null — DJP allocates. See section 6.2.4. |
tanggalFaktur | string | Yes | DDMMYYYY. See section 6.2.1. |
detailTransaksi | string | Yes | DJP transaction code (TD.003xx). Common values listed in section 6.10. |
masaPajak | string | Yes | 2-digit zero-padded month. "01" through "12". |
tahunPajak | string | Yes | 4-digit year. "2026" — note string, not integer. |
referensi | string | No | Free-form reference (typically the client's internal invoice number). |
idKeteranganTambahan | string | Conditional | Required when detailTransaksi is TD.00307 or TD.00308. Empty string otherwise. |
keteranganTambahan | string | Conditional | Required when detailTransaksi is TD.00307 or TD.00308. Empty string otherwise. |
refDoc | string | Conditional | Required when detailTransaksi is TD.00307 or TD.00308 (carries the underlying reference document number). |
Request body — counterparty fields
| Field | Type | Required | Description |
|---|---|---|---|
npwpPenjual | string | Yes | Seller (client) NPWP — 15 or 16 digits |
namaTokoPenjual | string | Yes | Seller's NPWP variant used to identify the issuing branch / store (typically a 22-digit composite) |
npwpPembeli | string | Yes | Buyer NPWP |
tkuPembeli | string | Yes | Buyer's 22-digit composite identifier (typically npwpPembeli + 6 trailing zeros) |
kdNegaraPembeli | string | Yes | ISO 3166-1 alpha-3 country code. "IDN" for domestic buyers. |
namaPembeli | string | Yes | Buyer name |
alamatPembeli | string | Yes | Buyer registered address |
emailPembeli | string (nullable) | No | Buyer email for sending the PDF Faktur; null when not collected |
idLainPembeli | string | No | Alternative identifier when the buyer is unregistered (passport for foreigners, NIK for individuals without NPWP). Empty string otherwise. |
nikPaspPembeli | string | No | The alternative-identifier value matching idLainPembeli |
Request body — line items (objekFaktur[])
Each invoice carries one or more line items in objekFaktur.
| Field | Type | Description |
|---|---|---|
brgJasa | string | "GOODS" or "SERVICES" |
kdBrgJasa | string | DJP goods/services code. "000000" is the generic placeholder for items without a specific code. |
namaBrgJasa | string | Description of the item |
satuanBrgJasa | string | Unit-of-measure code (UM.xxxx) |
hargaSatuan | number | Unit price in rupiah (no decimal separator) |
jmlBrgJasa | number | Quantity |
totalHarga | number | hargaSatuan × jmlBrgJasa |
diskon | number | Discount applied to this line; 0 when none |
cekDppLain | boolean | true when applying the PMK 131/2024 11/12 rule. See section 6.2.2. |
dpp | number | Contractual DPP (typically totalHarga − diskon) |
dppLain | number | DPP Nilai Lain — dpp × 11/12 under PMK 131/2024 |
tarifPpn | number | PPN rate as decimal fraction. 0.12 under PMK 131/2024. |
ppn | number | PPN amount — tarifPpn × dppLain |
tarifPpnbm | number | PPnBM rate as decimal fraction. 0 when not applicable. |
ppnbm | number | PPnBM amount. 0 when not applicable. |
Request body — totals and signing
| Field | Type | Description |
|---|---|---|
jumlahUangMuka | number | Used only when fgUangMuka or fgPelunasan is true; 0 otherwise |
totalDpp | number | Sum of objekFaktur[].dpp |
totalDppLain | number | Sum of objekFaktur[].dppLain |
totalPpn | number | Sum of objekFaktur[].ppn |
totalPpnbm | number | Sum of objekFaktur[].ppnbm |
npwpNikPenandatangan | string | Signer NIK — see section 6.2.3 |
tempatPenandatangan | string | Signing city |
passphrasePenandatangan | string | Certificate passphrase — sensitive |
userId | string | DJP-side user identifier |
kanal | string | DJP delivery channel — currently always "08" |
idKanal | string | Mirrors kanal |
Example request
POST /v2/efaktur/create-faktur-pk HTTP/1.1
Host: gateway-integration.sipajak.com
Authorization: Basic <base64-encoded credentials>
npwp: 1234567890123000
Content-Type: application/json
{
"fgUangMuka": false,
"fgPelunasan": false,
"nomorFaktur": null,
"tanggalFaktur": "11052026",
"detailTransaksi": "TD.00304",
"idKeteranganTambahan": "",
"keteranganTambahan": "",
"masaPajak": "05",
"tahunPajak": "2026",
"referensi": "INV-2026-05-001",
"npwpPenjual": "1234567890123000",
"namaTokoPenjual": "1234567890123000000000",
"npwpPembeli": "2345678901234000",
"tkuPembeli": "2345678901234000000000",
"kdNegaraPembeli": "IDN",
"namaPembeli": "PT Pembeli Contoh",
"alamatPembeli": "Jalan Contoh No. 1, Jakarta 12345",
"emailPembeli": "buyer@example.com",
"objekFaktur": [
{
"brgJasa": "SERVICES",
"kdBrgJasa": "000000",
"namaBrgJasa": "Jasa Analisa Laboratorium",
"satuanBrgJasa": "UM.0030",
"hargaSatuan": 4000000,
"jmlBrgJasa": 1,
"totalHarga": 4000000,
"diskon": 0,
"cekDppLain": true,
"dpp": 4000000,
"dppLain": 3666666.67,
"tarifPpn": 0.12,
"ppn": 440000,
"tarifPpnbm": 0,
"ppnbm": 0
}
],
"jumlahUangMuka": 0,
"totalDpp": 4000000,
"totalDppLain": 3666667,
"totalPpn": 440000,
"totalPpnbm": 0,
"npwpNikPenandatangan": "1234567890123000",
"tempatPenandatangan": "Jakarta",
"passphrasePenandatangan": "<certificate passphrase>",
"userId": "1234567890123000",
"kanal": "08",
"idKanal": "08"
}Example response — inline APPROVED
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"status": "1",
"statusMessage": "Success",
"result": {
"approvalSign": "Done",
"nomorFaktur": "04002600000000003",
"idFaktur": "18bbca3a-a706-4d96-bbf0-0f3de97b6f78",
"tanggalApproval": "2026-05-11",
"statusFaktur": "APPROVED",
"kodeApproval": ""
},
"uuid": "73896e3b-bb08-4e82-a234-4e6dac509b8b"
}
}Result fields
| Field | Type | Description |
|---|---|---|
result.nomorFaktur | string | DJP-issued 17-digit invoice serial. Preserve verbatim — it is the canonical identifier for subsequent operations. |
result.idFaktur | string | Sipajak-side correlation identifier (UUID on create, DJP-Pengganti-shaped on amend, absent on cancel) |
result.statusFaktur | string | One of APPROVED (signing completed inline) or SIGNING_IN_PROGRESS (signing happens asynchronously; poll check-status). See section 6.10 for the full enum. |
result.approvalSign | string | "Done" placeholder when signing completes inline; otherwise empty until signing completes, then populated with a Coretax document-management URL pointing to the signed PDF. |
result.tanggalApproval | string | YYYY-MM-DD on inline APPROVED; YYYY-MM-DD HH:mm:ss on async paths. |
result.kodeApproval | string | Currently always an empty string. The field exists for compatibility with older DJP contracts but is not populated for v2 transactions. |
Example response — soft error
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"status": "0",
"statusMessage": "npwpPembeli tidak ditemukan",
"uuid": "<DJP correlation id>"
}
}6.4.3 Amend (Pengganti) — POST /v2/efaktur/create-faktur-pk-amended
POST /v2/efaktur/create-faktur-pk-amended
Issues a replacement (Pengganti) for a previously issued invoice. The request body has the same shape as a create with three additions that link the new invoice to the original.
Additional fields on amend
| Field | Type | Description |
|---|---|---|
nomorFakturDiganti | string | DJP nomorFaktur of the invoice being replaced |
approvalSign | string | On amend requests, this field carries the original invoice's nomorFaktur (it is repurposed; on responses approvalSign carries the document URL — see section 6.10) |
revokeFlag | boolean | false for a fresh amend. Set to true only when amending an invoice currently in MENUNGGU_PENGGANTIAN state (i.e. a previous amend was pending and is being superseded). |
The amend response carries idFaktur populated with the new 17-digit Pengganti number (DJP increments a digit in the original); nomorFaktur is not on the amend response. The initial statusFaktur is typically SIGNING_IN_PROGRESS — clients should follow up via check-status.
6.4.4 Cancel — POST /v2/efaktur/cancel-faktur-pk
POST /v2/efaktur/cancel-faktur-pk
Cancels a previously issued invoice. Once an invoice has been included in a filed SPT Masa PPN, cancellation typically requires a Pengganti workflow rather than direct cancel — Sipajak enforces this client-side; direct calls to DJP after the deadline will be rejected by DJP.
Request body
Minimal: identify the invoice by nomorFaktur, supply the signing fields. The kdJenisTransaksi field echoes the detailTransaksi of the original invoice.
{
"nomorFaktur": "03002600000000001",
"kdJenisTransaksi": "TD.00303",
"kanal": "08",
"idKanal": "08",
"npwpPenjual": "1234567890123000",
"npwpNikPenandatangan": "1234567890123000",
"tempatPenandatangan": "Jakarta",
"passphrasePenandatangan": "<certificate passphrase>",
"userId": "1234567890123000"
}On success the response data.result echoes the cancelled invoice's nomorFaktur and tanggalApproval (of the original), with statusFaktur = CANCELED.
6.4.5 Retur — DJP-prepopulated
POST /v2/efaktur/create-retur-faktur-pk
Despite the verb "create" in the path, this endpoint lists DJP-prepopulated returns for a period. The buyer initiates the retur on their side; DJP places the resulting retur record on the seller's prepopulated list; this endpoint surfaces that list for the seller to acknowledge.
Request body carries the period (masaPajak, tahunPajak) and pagination; the response carries an array of retur records each with nomorRetur, nomorFaktur (the original being returned), and timestamps. There is no client-initiated retur-create on output invoices — the buyer is the source of the retur.
POST /v2/efaktur/cancel-retur-faktur-pk
Cancels a previously acknowledged retur. Request body identifies the retur by nomorRetur, with the standard signing fields.
6.5 Dokumen Keluaran
Equivalent documents (Dokumen yang Dipersamakan dengan Faktur Pajak) on the seller side. These are issued in lieu of a standard Faktur Pajak for transaction types DJP permits — typically those backed by an underlying physical document such as a Pemberitahuan Impor Barang, a utility bill, or a customs document.
The lifecycle and operational shape mirror Pajak Keluaran exactly; the deltas are the classifier codes that identify the underlying document type, plus a few renames at the wire level.
6.5.1 Endpoint summary
| Method | Path | Purpose |
|---|---|---|
| POST | /v2/efaktur/create-document-pk | Issue a new equivalent document |
| POST | /v2/efaktur/create-document-pk-amended | Issue a Pengganti |
| POST | /v2/efaktur/cancel-document-pk | Cancel an issued equivalent document |
| POST | /v2/efaktur/create-retur-document-pk | Create a retur on an equivalent document |
| POST | /v2/efaktur/cancel-retur-document-pk | Cancel a previously-issued retur |
6.5.2 Delta from Pajak Keluaran
The Dokumen Keluaran payload is structurally Faktur Keluaran minus the advance-payment fields and the alternative-buyer-identity fields, plus three classifier codes.
Fields renamed from PK to DK
| Pajak Keluaran field | Dokumen Keluaran field |
|---|---|
| nomorFaktur | nomorDokumen |
| tanggalFaktur | tanggalDokumen |
| nomorFakturDiganti | nomorDokumenDiganti |
| totalDpp | jumlahDpp |
| totalPpn | jumlahPpn |
| totalPpnbm | jumlahPpnbm |
Fields added on DK
| Field | Type | Description |
|---|---|---|
dokumenTransaksi | string | Underlying document type. OSD.006xx family. OSD.00603 = Dokumen Kawasan Berikat is the most commonly observed value. |
kodeDokumen | string (nullable) | Supplementary classification (OSD.007xx). null when not applicable. |
kdTransaksi | string | High-level category: "DELIVERY" (domestic) or "EXPORT" |
isCreatedByBuyer | boolean | Always false for seller-side issuance |
fgPengganti | string | TD.00400 for initial issue, TD.00401 for Pengganti |
namaPenjualPembeli | string | Unified counterparty name (DK collapses the separate namaPenjual/namaPembeli fields PK uses) |
alamatPenjualPembeli | string | Unified counterparty address |
npwpPenjualPembeli | string | Unified counterparty NPWP |
npwpPenerbit | string | Issuer NPWP-16 (replaces PK's npwpPenjual) |
Fields removed compared to PK
DK has no advance-payment fields (fgUangMuka, fgPelunasan, jumlahUangMuka), no alternative-buyer-identity fields (idLainPembeli, nikPaspPembeli, kdNegaraPembeli, tkuPembeli, emailPembeli), no namaTokoPenjual, no idKeteranganTambahan/keteranganTambahan/refDoc, and no totalDppLain (DK uses jumlahDpp only).
6.5.3 Response shape
The DK response shape mirrors PK with three differences. DK issues a free-form nomorDokumen / idDokumen rather than a DJP-assigned 17-digit nomorFaktur. There is no QR code in the response — equivalent documents are not issued with a DJP-assigned NSFP. The approvalSign field on a DK response is populated with a Coretax document-management URL pointing to the signed PDF (whereas on PK the same field carries "Done" for inline-approved invoices).
6.6 Pajak Masukan (PM)
Input VAT invoices the client receives from its suppliers. The flow inverts the PK shape: rather than the client creating the invoice, DJP already has it (the supplier issued it via their own PK flow), and the client claims it. Sipajak surfaces two operations on a claimed invoice: a credit/uncredit toggle (whether to claim the input VAT credit this period), and acknowledgment of supplier-initiated amendments and cancellations.
6.6.1 Endpoint summary
| Method | Path | Purpose |
|---|---|---|
| POST | /v2/efaktur/create-faktur-pm | Prepopulate / claim an incoming invoice |
| POST | /v2/efaktur/confirmation-amended-cancel-faktur-pm | Acknowledge a supplier-initiated amend or cancel |
| POST | /v2/efaktur/create-retur-faktur-pm | Create a return on a claimed invoice |
| POST | /v2/efaktur/cancel-retur-faktur-pm | Cancel a previously-issued return |
6.6.2 Create / Prepopulate
POST /v2/efaktur/create-faktur-pm
Two distinct modes share this single endpoint. The mode is implicit in which fields are populated.
| Mode | Trigger | Behaviour |
|---|---|---|
| Prepopulate | Minimal body: nomorFaktur, tahunPajak, npwpPenjual (+ credit-period fields when claiming credit immediately) | Sipajak pulls the full invoice detail from DJP and stores it. The response carries the full FormData populated by DJP, which the client can then display to the user. |
| Credit / Uncredit toggle | After prepopulate, calling again with PeriodCredit and YearCredit set toggles whether this invoice's input VAT is claimed in the specified period | Updates the credit-period assignment. The same invoice can be uncredited and re-credited freely until the relevant SPT Masa PPN is filed. |
Example request — prepopulate
POST /v2/efaktur/create-faktur-pm HTTP/1.1
Host: gateway-integration.sipajak.com
Authorization: Basic <base64-encoded credentials>
npwp: 1234567890123000
Content-Type: application/json
{
"nomorFaktur": "04002600000000002",
"tahunPajak": "2026",
"npwpPenjual": "3201234567890000",
"npwpPembeli": "1234567890123000",
"isCredited": false,
"PeriodCredit": null,
"YearCredit": null
}Response shape
Nested PascalCase envelope. Unlike the rest of Sipajak — which uses camelCase / snake_case flat fields — Pajak Masukan responses carry a nested PascalCase envelope under data.dataFaktur.FormData. This is a direct passthrough of DJP's response schema. Expect keys such as TransactionDocumentData, BuyerInformationData, SellerInformationData, and InvoiceDate. Parse defensively. Treat this nested envelope as DJP-side and do not rely on the casing matching anything elsewhere in the Sipajak API.
{
"status_code": 200,
"message": "OK",
"data": {
"status": "1",
"statusMessage": "Success",
"dataFaktur": {
"FormData": {
"InvoiceDate": "2026-04-15T00:00:00",
"TransactionDocumentData": { ... },
"BuyerInformationData": { ... },
"SellerInformationData": { ... },
"ItemList": [ ... ]
}
}
}
}6.6.3 Confirmation of supplier-initiated amend or cancel
POST /v2/efaktur/confirmation-amended-cancel-faktur-pm
When a supplier issues a Pengganti or cancels an invoice the client has already claimed, DJP places the change in a "waiting for confirmation" state. The client uses this endpoint to acknowledge — either accepting the supplier's amend (which then propagates to the client's view) or rejecting it.
Request body identifies the affected invoice by nomorFaktur and carries an action flag indicating accept or reject.
6.6.4 Retur on input invoice
POST /v2/efaktur/create-retur-faktur-pm
Records a return on a claimed input invoice. The cancel-retur counterpart reverses a previously-issued retur.
6.7 Dokumen Masukan
Equivalent documents claimed by the client as input — for sources that do not produce a standard Faktur Pajak. The endpoints mirror Dokumen Keluaran from the receiving side: the schema is nearly identical to DK with the roles of seller and buyer swapped, plus a credit-decision field that mirrors the PM credit toggle.
6.7.1 Endpoint summary
| Method | Path | Purpose |
|---|---|---|
| POST | /v2/efaktur/create-document-pm | Claim an incoming equivalent document |
| POST | /v2/efaktur/create-document-pm-amended | Acknowledge or issue a Pengganti |
| POST | /v2/efaktur/cancel-document-pm | Cancel a claimed document |
| POST | /v2/efaktur/create-retur-document-pm | Create a retur |
| POST | /v2/efaktur/cancel-retur-document-pm | Cancel a previously-issued retur |
6.7.2 Delta from Dokumen Keluaran
| Aspect | Dokumen Keluaran | Dokumen Masukan |
|---|---|---|
| Issuer of the document | Client | Counterparty |
| npwpPenerbit value | Client's own NPWP | Counterparty's NPWP |
| npwpPenjualPembeli value | Counterparty's NPWP | Client's own NPWP |
| isCreatedByBuyer | false | true |
| Credit decision | Not applicable | is_credit field controls whether to claim the input VAT credit |
| Cancellation initiative | Client-initiated (Sipajak signs and submits) | Buyer requests cancel; DJP routes back to issuer for approval; status passes through WAITING_FOR_CANCELLATION |
6.8 Utility
Two cross-cutting helper endpoints used by integrators across the PK/DK/PM/Dokumen-PM groups: scan (OCR a faktur image or PDF and extract structured fields) and check-status (refresh DJP-side status of a previously created or claimed document).
6.8.1 Scan — POST /v2/efaktur/scan
POST /v2/efaktur/scan
Accepts an uploaded faktur file (PDF / JPEG / PNG) and runs Tesseract OCR to extract structured fields. Asynchronous — the immediate response carries a job_id; final extracted fields are delivered via webhook or retrieved by polling.
Request — multipart/form-data
| Form field | Type | Required | Description |
|---|---|---|---|
| file | binary | Yes | PDF, JPEG, or PNG. Maximum 10 MB. Other MIME types return HTTP 400. |
| webhook_url | string (URL) | Yes | HTTPS URL Sipajak POSTs the extracted-fields payload to when processing completes. |
| requestId | string | No | Client-supplied correlation identifier — Sipajak echoes it on the webhook payload. |
Response — 202 Accepted
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
{
"status_code": 202,
"message": "OK",
"data": {
"job_id": "f2fbc0c2-e917-40db-b93c-b71d50cdaa92",
"status": "PENDING"
}
}Polling alternative
GET /v2/efaktur/scan/{job_id}
When a webhook is impractical, clients can poll this endpoint until status reaches a terminal state. The response shape exposes status, progress (0-100), processing_time_ms, created_at, completed_time, and on FAILED, errorMessage.
| Status | Meaning |
|---|---|
PENDING | Queued for processing |
PROCESSING | OCR running |
COMPLETED | Extracted-fields payload available |
FAILED | Processing failed; errorMessage carries detail |
No per-field confidence scoring. Sipajak's scan response carries the OCR-extracted text only. There is no per-field confidence score and no overall confidence metric. A low-confidence outcome surfaces as missing or malformed fields in the extracted payload — clients must validate the structured output themselves before using it.
6.8.2 Check status — POST /v2/efaktur/check-status
POST /v2/efaktur/check-status
Refreshes the DJP-side status of one or more previously created or claimed documents. Useful after an asynchronous signing flow (when create returned SIGNING_IN_PROGRESS) and for periodic reconciliation.
The immediate response is not the DJP status. check-status always returns HTTP 201 OK with data: null, regardless of whether DJP returned a success or a business error. The actual DJP outcome is recorded on the underlying document in Sipajak — re-fetch the document via the Sipajak document-detail endpoint (or the relevant PostgreSQL row) to read the resolved status. Clients that treat the immediate response as authoritative will build broken reconciliation logic.
Request body
The request identifies the document by its Sipajak-internal id, not by its DJP-side nomorFaktur or nomorSeriFakturPajak. The server constructs the DJP payload internally.
{
"dokumen_masukan_id": [
"30bbf6ec-c8c9-4ce6-bdbf-1cfac9aa6d57"
]
}When the array has one element, the DJP call runs inline within the request thread. When it has more than one, Sipajak marks each row in_progress and enqueues background work; the response returns immediately. Either way, the response shape is the same.
No client-side caching. Unlike VSWP — which caches lookups with a 90-day TTL — check-status hits DJP on every call. Throttle clients accordingly. As a rule of thumb, call check-status only when displaying a document detail page or when reconciling against a filed SPT; avoid background polling.
6.9 Status enums
DJP returns a small enum of status values on result.statusFaktur (PK and PM) and result.statusDokumen (DK and Dokumen PM). The two enums share an identical value space.
| Value | Meaning |
|---|---|
APPROVED | Signing completed; document is in normal state and effective |
SIGNING_IN_PROGRESS | Signing is happening asynchronously at DJP. Final status will be APPROVED or SAVED_INVALID. Poll check-status. |
AMENDED | Document has been replaced by a Pengganti |
CANCELED | Document has been cancelled |
WAITING_FOR_AMENDMENT | Buyer-side: a supplier-initiated Pengganti is pending the buyer's confirmation. Use the confirmation-amended-cancel-faktur-pm endpoint to accept or reject. |
WAITING_FOR_CANCELLATION | Buyer-side: a supplier-initiated cancellation is pending the buyer's confirmation. |
SAVED_INVALID | Signing failed or DJP-side validation rejected the document |
CREDITED | Buyer-side: input VAT has been claimed (PM/Dokumen-PM only) |
UNCREDIT | Buyer-side: input VAT has been released back (PM/Dokumen-PM only) |
6.10 Error catalogue
DJP returns specific Bahasa Indonesia messages for business-level failures, surfacing them in data.statusMessage. The table below lists the messages observed in production traffic on the create-faktur-pk endpoint, ordered by frequency. Other endpoints use the same message space — counterparty validation errors, signing-authority errors, and schema-rejection errors all follow the same pattern.
| DJP message | Cause |
|---|---|
| npwpPembeli tidak ditemukan | Buyer NPWP is not in DJP's master data. Confirm the NPWP with the buyer or run a VSWP lookup. |
| tkuPembeli tidak valid | tkuPembeli value is malformed. Expected: npwpPembeli + 6 trailing digits (typically zeros), total 22 characters. |
| NationalID = {nik} tidak valid atau tidak ditemukan! | When the buyer is identified by NIK (idLainPembeli set), the NIK lookup at DJP failed. |
| [ERR_*] - [Field] should not be empty | DJP-side schema rejection. A required field was empty. Common case: TD.00307 / TD.00308 invoices missing idKeteranganTambahan / keteranganTambahan / refDoc. |
| NPWPNikPenandatangan ... tidak memiliki hak untuk membuat Faktur/Dokumen | Signing-authority error: the signer NIK is not on the organisation's authorised-signer list at DJP. Resolve by registering the signer via the Organization module's signer-management interface (out of scope of this document). |
6.11 Error handling reference
| Situation | What the client sees |
|---|---|
| Successful operation | HTTP 200, data.status = "1", data.result carries the payload |
| DJP business-level failure | HTTP 200, data.status = "0", data.statusMessage carries the diagnostic |
| Signing inline succeeded | result.statusFaktur = APPROVED; result.approvalSign = "Done" |
| Signing happens asynchronously | result.statusFaktur = SIGNING_IN_PROGRESS; result.approvalSign = empty. Poll check-status until terminal. |
| Scan accepted | HTTP 202, data.job_id and data.status = "PENDING" |
| File too large (>10 MB) or wrong MIME | HTTP 400 with explicit message |
| check-status accepted | HTTP 201, data = null. Refresh the document detail to read the resolved status. |
| Authentication failure | HTTP 401 |
| NPWP header missing or not registered | HTTP 403 |
| Server error | HTTP 500 |