e-Faktur

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.

MethodPathFungsi
GET/v1/ref/countryISO 3166 country codes (3-letter alpha-3)
GET/v1/ref/unitUnits of measure (DJP "UM.xxxx" codes)
GET/v1/ref/transaction-codeDJP transaction codes (TD.003xx)
GET/v1/ref/goods-servicesGoods and services classification codes
GET/v1/ref/additional-infoAdditional-information codes used with TD.00307 / TD.00308
POST/v2/efaktur/create-faktur-pkIssue a new sales invoice
POST/v2/efaktur/create-faktur-pk-amendedIssue a Pengganti (replacement) of an existing invoice
POST/v2/efaktur/cancel-faktur-pkCancel an existing invoice
POST/v2/efaktur/create-retur-faktur-pkList DJP-prepopulated returns for a period — see note below
POST/v2/efaktur/cancel-retur-faktur-pkCancel a previously-issued return
POST/v2/efaktur/create-document-pkIssue a new equivalent document
POST/v2/efaktur/create-document-pk-amendedIssue a Pengganti
POST/v2/efaktur/cancel-document-pkCancel an issued equivalent document
POST/v2/efaktur/create-retur-document-pkCreate a retur on an equivalent document
POST/v2/efaktur/cancel-retur-document-pkCancel a previously-issued retur
POST/v2/efaktur/create-faktur-pmPrepopulate / claim an incoming invoice
POST/v2/efaktur/confirmation-amended-cancel-faktur-pmAcknowledge a supplier-initiated amend or cancel
POST/v2/efaktur/create-retur-faktur-pmCreate a return on a claimed invoice
POST/v2/efaktur/cancel-retur-faktur-pmCancel a previously-issued return
POST/v2/efaktur/create-document-pmClaim an incoming equivalent document
POST/v2/efaktur/create-document-pm-amendedAcknowledge or issue a Pengganti
POST/v2/efaktur/cancel-document-pmCancel a claimed document
POST/v2/efaktur/create-retur-document-pmCreate a retur
POST/v2/efaktur/cancel-retur-document-pmCancel 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.

GroupEndpointsPurpose
Reference data5Catalogue 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)5Output VAT invoices issued by the client to its customers. The canonical flow: create, amend (Pengganti), cancel, retur, cancel retur.
Dokumen Keluaran (DK)5Equivalent 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)4Input 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 Masukan5Equivalent documents the client manually claims as input — for non-faktur sources such as customs documents or retail receipts.
Utility3Two 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 2026

Response 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:

FieldTypeDescription
npwpNikPenandatanganstringNIK of the human signer authorised to sign on behalf of the organisation. Distinct from npwpPenjual (the organisation NPWP).
userIdstringDJP-side user identifier for the signer. Usually identical to npwpNikPenandatangan.
tempatPenandatanganstringCity where the document is signed (free-form short string).
passphrasePenandatanganstringPlaintext 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

MethodPathCatalogue
GET/v1/ref/countryISO 3166 country codes (3-letter alpha-3)
GET/v1/ref/unitUnits of measure (DJP "UM.xxxx" codes)
GET/v1/ref/transaction-codeDJP transaction codes (TD.003xx)
GET/v1/ref/goods-servicesGoods and services classification codes
GET/v1/ref/additional-infoAdditional-information codes used with TD.00307 / TD.00308

6.3.2 Common query parameters

All five endpoints accept the same pagination and search parameters.

ParameterTypeRequiredDescription
keywordstringNoFree-text search across code and name fields
pagestring (numeric)No1-indexed page number. Default 1.
limitstring (numeric)NoPage 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: 1234567890123000
HTTP/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

MethodPathPurpose
POST/v2/efaktur/create-faktur-pkIssue a new sales invoice
POST/v2/efaktur/create-faktur-pk-amendedIssue a Pengganti (replacement) of an existing invoice
POST/v2/efaktur/cancel-faktur-pkCancel an existing invoice
POST/v2/efaktur/create-retur-faktur-pkList DJP-prepopulated returns for a period — see note below
POST/v2/efaktur/cancel-retur-faktur-pkCancel 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

FieldTypeRequiredDescription
fgUangMukabooleanYestrue for an advance-payment invoice. Use false in the standard case.
fgPelunasanbooleanYestrue for a final-settlement invoice that closes out a previous advance. Use false in the standard case.
nomorFakturstring (nullable)YesLeave empty or null — DJP allocates. See section 6.2.4.
tanggalFakturstringYesDDMMYYYY. See section 6.2.1.
detailTransaksistringYesDJP transaction code (TD.003xx). Common values listed in section 6.10.
masaPajakstringYes2-digit zero-padded month. "01" through "12".
tahunPajakstringYes4-digit year. "2026" — note string, not integer.
referensistringNoFree-form reference (typically the client's internal invoice number).
idKeteranganTambahanstringConditionalRequired when detailTransaksi is TD.00307 or TD.00308. Empty string otherwise.
keteranganTambahanstringConditionalRequired when detailTransaksi is TD.00307 or TD.00308. Empty string otherwise.
refDocstringConditionalRequired when detailTransaksi is TD.00307 or TD.00308 (carries the underlying reference document number).

Request body — counterparty fields

FieldTypeRequiredDescription
npwpPenjualstringYesSeller (client) NPWP — 15 or 16 digits
namaTokoPenjualstringYesSeller's NPWP variant used to identify the issuing branch / store (typically a 22-digit composite)
npwpPembelistringYesBuyer NPWP
tkuPembelistringYesBuyer's 22-digit composite identifier (typically npwpPembeli + 6 trailing zeros)
kdNegaraPembelistringYesISO 3166-1 alpha-3 country code. "IDN" for domestic buyers.
namaPembelistringYesBuyer name
alamatPembelistringYesBuyer registered address
emailPembelistring (nullable)NoBuyer email for sending the PDF Faktur; null when not collected
idLainPembelistringNoAlternative identifier when the buyer is unregistered (passport for foreigners, NIK for individuals without NPWP). Empty string otherwise.
nikPaspPembelistringNoThe alternative-identifier value matching idLainPembeli

Request body — line items (objekFaktur[])

Each invoice carries one or more line items in objekFaktur.

FieldTypeDescription
brgJasastring"GOODS" or "SERVICES"
kdBrgJasastringDJP goods/services code. "000000" is the generic placeholder for items without a specific code.
namaBrgJasastringDescription of the item
satuanBrgJasastringUnit-of-measure code (UM.xxxx)
hargaSatuannumberUnit price in rupiah (no decimal separator)
jmlBrgJasanumberQuantity
totalHarganumberhargaSatuan × jmlBrgJasa
diskonnumberDiscount applied to this line; 0 when none
cekDppLainbooleantrue when applying the PMK 131/2024 11/12 rule. See section 6.2.2.
dppnumberContractual DPP (typically totalHarga − diskon)
dppLainnumberDPP Nilai Lain — dpp × 11/12 under PMK 131/2024
tarifPpnnumberPPN rate as decimal fraction. 0.12 under PMK 131/2024.
ppnnumberPPN amount — tarifPpn × dppLain
tarifPpnbmnumberPPnBM rate as decimal fraction. 0 when not applicable.
ppnbmnumberPPnBM amount. 0 when not applicable.

Request body — totals and signing

FieldTypeDescription
jumlahUangMukanumberUsed only when fgUangMuka or fgPelunasan is true; 0 otherwise
totalDppnumberSum of objekFaktur[].dpp
totalDppLainnumberSum of objekFaktur[].dppLain
totalPpnnumberSum of objekFaktur[].ppn
totalPpnbmnumberSum of objekFaktur[].ppnbm
npwpNikPenandatanganstringSigner NIK — see section 6.2.3
tempatPenandatanganstringSigning city
passphrasePenandatanganstringCertificate passphrase — sensitive
userIdstringDJP-side user identifier
kanalstringDJP delivery channel — currently always "08"
idKanalstringMirrors 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

FieldTypeDescription
result.nomorFakturstringDJP-issued 17-digit invoice serial. Preserve verbatim — it is the canonical identifier for subsequent operations.
result.idFakturstringSipajak-side correlation identifier (UUID on create, DJP-Pengganti-shaped on amend, absent on cancel)
result.statusFakturstringOne of APPROVED (signing completed inline) or SIGNING_IN_PROGRESS (signing happens asynchronously; poll check-status). See section 6.10 for the full enum.
result.approvalSignstring"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.tanggalApprovalstringYYYY-MM-DD on inline APPROVED; YYYY-MM-DD HH:mm:ss on async paths.
result.kodeApprovalstringCurrently 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

FieldTypeDescription
nomorFakturDigantistringDJP nomorFaktur of the invoice being replaced
approvalSignstringOn amend requests, this field carries the original invoice's nomorFaktur (it is repurposed; on responses approvalSign carries the document URL — see section 6.10)
revokeFlagbooleanfalse 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

MethodPathPurpose
POST/v2/efaktur/create-document-pkIssue a new equivalent document
POST/v2/efaktur/create-document-pk-amendedIssue a Pengganti
POST/v2/efaktur/cancel-document-pkCancel an issued equivalent document
POST/v2/efaktur/create-retur-document-pkCreate a retur on an equivalent document
POST/v2/efaktur/cancel-retur-document-pkCancel 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 fieldDokumen Keluaran field
nomorFakturnomorDokumen
tanggalFakturtanggalDokumen
nomorFakturDigantinomorDokumenDiganti
totalDppjumlahDpp
totalPpnjumlahPpn
totalPpnbmjumlahPpnbm

Fields added on DK

FieldTypeDescription
dokumenTransaksistringUnderlying document type. OSD.006xx family. OSD.00603 = Dokumen Kawasan Berikat is the most commonly observed value.
kodeDokumenstring (nullable)Supplementary classification (OSD.007xx). null when not applicable.
kdTransaksistringHigh-level category: "DELIVERY" (domestic) or "EXPORT"
isCreatedByBuyerbooleanAlways false for seller-side issuance
fgPenggantistringTD.00400 for initial issue, TD.00401 for Pengganti
namaPenjualPembelistringUnified counterparty name (DK collapses the separate namaPenjual/namaPembeli fields PK uses)
alamatPenjualPembelistringUnified counterparty address
npwpPenjualPembelistringUnified counterparty NPWP
npwpPenerbitstringIssuer 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

MethodPathPurpose
POST/v2/efaktur/create-faktur-pmPrepopulate / claim an incoming invoice
POST/v2/efaktur/confirmation-amended-cancel-faktur-pmAcknowledge a supplier-initiated amend or cancel
POST/v2/efaktur/create-retur-faktur-pmCreate a return on a claimed invoice
POST/v2/efaktur/cancel-retur-faktur-pmCancel 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.

ModeTriggerBehaviour
PrepopulateMinimal 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 toggleAfter prepopulate, calling again with PeriodCredit and YearCredit set toggles whether this invoice's input VAT is claimed in the specified periodUpdates 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

MethodPathPurpose
POST/v2/efaktur/create-document-pmClaim an incoming equivalent document
POST/v2/efaktur/create-document-pm-amendedAcknowledge or issue a Pengganti
POST/v2/efaktur/cancel-document-pmCancel a claimed document
POST/v2/efaktur/create-retur-document-pmCreate a retur
POST/v2/efaktur/cancel-retur-document-pmCancel a previously-issued retur

6.7.2 Delta from Dokumen Keluaran

AspectDokumen KeluaranDokumen Masukan
Issuer of the documentClientCounterparty
npwpPenerbit valueClient's own NPWPCounterparty's NPWP
npwpPenjualPembeli valueCounterparty's NPWPClient's own NPWP
isCreatedByBuyerfalsetrue
Credit decisionNot applicableis_credit field controls whether to claim the input VAT credit
Cancellation initiativeClient-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 fieldTypeRequiredDescription
filebinaryYesPDF, JPEG, or PNG. Maximum 10 MB. Other MIME types return HTTP 400.
webhook_urlstring (URL)YesHTTPS URL Sipajak POSTs the extracted-fields payload to when processing completes.
requestIdstringNoClient-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.

StatusMeaning
PENDINGQueued for processing
PROCESSINGOCR running
COMPLETEDExtracted-fields payload available
FAILEDProcessing 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.

ValueMeaning
APPROVEDSigning completed; document is in normal state and effective
SIGNING_IN_PROGRESSSigning is happening asynchronously at DJP. Final status will be APPROVED or SAVED_INVALID. Poll check-status.
AMENDEDDocument has been replaced by a Pengganti
CANCELEDDocument has been cancelled
WAITING_FOR_AMENDMENTBuyer-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_CANCELLATIONBuyer-side: a supplier-initiated cancellation is pending the buyer's confirmation.
SAVED_INVALIDSigning failed or DJP-side validation rejected the document
CREDITEDBuyer-side: input VAT has been claimed (PM/Dokumen-PM only)
UNCREDITBuyer-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 messageCause
npwpPembeli tidak ditemukanBuyer NPWP is not in DJP's master data. Confirm the NPWP with the buyer or run a VSWP lookup.
tkuPembeli tidak validtkuPembeli 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 emptyDJP-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/DokumenSigning-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

SituationWhat the client sees
Successful operationHTTP 200, data.status = "1", data.result carries the payload
DJP business-level failureHTTP 200, data.status = "0", data.statusMessage carries the diagnostic
Signing inline succeededresult.statusFaktur = APPROVED; result.approvalSign = "Done"
Signing happens asynchronouslyresult.statusFaktur = SIGNING_IN_PROGRESS; result.approvalSign = empty. Poll check-status until terminal.
Scan acceptedHTTP 202, data.job_id and data.status = "PENDING"
File too large (>10 MB) or wrong MIMEHTTP 400 with explicit message
check-status acceptedHTTP 201, data = null. Refresh the document detail to read the resolved status.
Authentication failureHTTP 401
NPWP header missing or not registeredHTTP 403
Server errorHTTP 500