API VSWP (Validasi Status Wajib Pajak) memvalidasi NPWP atau NIK langsung ke DJP Coretax, cocok untuk onboarding nasabah, KYC fintech, dan verifikasi vendor. Tersedia lookup tunggal real-time dan alur bulk berbasis job.
| Method | Path | Fungsi |
|---|---|---|
| POST | /v2/vswp | Single taxpayer lookup |
| POST | /v1/vswp/bulking | Submit a bulk lookup job |
| GET | /v1/vswp/{id} | Poll status of a bulk job |
| GET | /v1/vswp/{id}/export | Download CSV result of a completed bulk job |
VSWP (Validasi Status Wajib Pajak) is Sipajak's interface to DJP's Coretax CTAS (Taxpayer Application Services). It answers a single question: is this NPWP or NIK registered with DJP, and what is its profile?
5.1 Endpoint summary
| Method | Path | Purpose |
|---|---|---|
| POST | /v2/vswp | Single taxpayer lookup |
| POST | /v1/vswp/bulking | Submit a bulk lookup job |
| GET | /v1/vswp/{id} | Poll status of a bulk job |
| GET | /v1/vswp/{id}/export | Download CSV result of a completed bulk job |
5.2 Single lookup
POST /v2/vswp
Looks up a single NPWP or NIK against DJP Coretax CTAS and returns the taxpayer profile.
Soft-error endpoint. This is a DJP-passthrough endpoint. HTTP 200 is returned even when the taxpayer is not found. Inspect data.status ("1" = success, "0" = business failure).
Results are cached server-side for 90 days keyed on (npwp, tujuan). Repeat lookups within the TTL window return in roughly 10ms without consulting DJP.
No format validation. The endpoint accepts any string in body.data.npwp and forwards it to DJP. Malformed identifiers receive the same "Wajib Pajak tidak ditemukan" response as non-existent ones. Validate format client-side if you need strict checking — 15-digit legacy NPWP, 16-digit harmonised NPWP, or 16-digit NIK.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | HTTP Basic Auth (see section 2.2) |
npwp | Yes | The organisation NPWP this call acts on behalf of (see section 2.3) |
Content-Type | Yes | application/json |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
npwp | string | Yes | The identifier to look up. Accepts 15-digit legacy NPWP, 16-digit harmonised NPWP, or 16-digit NIK. Not format-validated by the endpoint. |
tujuan | string | Yes | Business reason for the lookup. Valid values: "Validasi NPWP" or "Konfirmasi NPWP". Used for audit-trail labelling; both produce identical responses. |
Example request
POST /v2/vswp HTTP/1.1
Host: gateway-integration.sipajak.com
Authorization: Basic <base64-encoded credentials>
npwp: 1234567890123000
Content-Type: application/json
{
"npwp": "3201234567890000",
"tujuan": "Validasi NPWP"
}Response — success (taxpayer found)
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"status": "1",
"statusMessage": "Success",
"result": {
"npwp": "3201234567890000",
"nama": "Budi Santoso",
"alamat": "Jalan Contoh No. 1, Jakarta 12345",
"statusWp": "VALID",
"statusSpt": "VALID"
},
"uuid": "9fc2be05-9882-42da-8f80-02050aa84393"
}
}Response — not found (or malformed input)
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"status": "0",
"statusMessage": "Wajib Pajak tidak ditemukan",
"uuid": "b9bebf93-102c-4d7b-a884-80b2c5490e23"
}
}Response data fields
| Field | Type | Description |
|---|---|---|
status | string | "1" for success (result present), "0" for failure (result absent) |
statusMessage | string | Human-readable outcome. "Success" on success; DJP error message on failure |
data.result.npwp | string | The identifier as DJP records it |
data.result.nama | string | Taxpayer name (individual or entity) |
data.result.alamat | string | Registered address |
data.result.statusWp | string | Taxpayer status. "VALID" indicates active |
data.result.statusSpt | string | SPT filing status. "VALID" indicates current on filings |
uuid | string | Server-generated request identifier for traceability |
5.3 Bulk lookup flow
The bulk flow is a standard submit-poll-download pattern. There are no webhooks; the client polls for completion.
5.3.1 Step 1 — Submit
POST /v1/vswp/bulking
Submits a CSV file of NPWPs/NIKs for asynchronous validation. The response carries a job identifier used for polling and download.
Async-job endpoint. The response envelope contains only job_id — no status, statusMessage, or uuid. See section 3.1.1. Bulk submissions are not idempotent. Submitting the same file twice produces two job_ids and two jobs.
Request
| Field | Type | Required | Description |
|---|---|---|---|
Content-Type | header | Yes | multipart/form-data |
file | form field (binary) | Yes | CSV file with one identifier per row. First row may be a header ("npwp"). |
Example CSV content (header row plus 2 data rows):
NPWP,Tujuan
3201234567890000,Validasi NPWP
3301234567890000,Validasi NPWPNotes on the CSV format:
- Header row is required — first row must contain the column names
NPWPandTujuan(case-sensitive). - NPWP column — one identifier per row. Accepts 15-digit legacy NPWP, 16-digit harmonised NPWP, or 16-digit NIK. Same format rules as the single-lookup endpoint.
- Tujuan column — business reason for the lookup. Use
Validasi NPWPorKonfirmasi NPWP. The value applies per row, so a single file can mix purposes.
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"status_code": 200,
"message": "OK",
"data": {
"job_id": "70a6abf1-595f-4b24-ac4f-b368f4ebf671"
}
}5.3.2 Step 2 — Poll for status
GET /v1/vswp/{id}
Returns the current state of a bulk job. Poll with a 5- to 10-second interval until data.status equals "COMPLETED". Do not poll more frequently than once per second.
Path parameters
| Parameter | Description |
|---|---|
id | The job_id returned by the submit call (UUID) |
Response — processing
{
"status_code": 200,
"message": "OK",
"data": {
"job_vswp_id": "70a6abf1-595f-4b24-ac4f-b368f4ebf671",
"inprogress": 3,
"total": 10,
"status": "PROCESSING",
"created_time": "2026-05-11T16:00:00.000Z",
"log_vswp": [ /* per-row results, populated incrementally */ ]
}
}Response — completed
{
"status_code": 200,
"message": "OK",
"data": {
"job_vswp_id": "70a6abf1-595f-4b24-ac4f-b368f4ebf671",
"inprogress": 10,
"total": 10,
"status": "COMPLETED",
"created_time": "2026-05-11T16:00:00.000Z",
"log_vswp": [
{
"request": {
"data": { "npwp": "3201234567890000", "tujuan": "Validasi NPWP" },
"params": {}
},
"response": {
"status": "1",
"statusMessage": "Success",
"result": {
"npwp": "3201234567890000",
"nama": "Budi Santoso",
"alamat": "Jalan Contoh No. 1, Jakarta 12345",
"statusWp": "VALID",
"statusSpt": "VALID"
}
},
"response_time": "0.47"
}
]
}
}Response data fields
| Field | Type | Description |
|---|---|---|
job_vswp_id | string (uuid) | The job identifier. Same value as job_id from submit response. |
inprogress | integer | Rows already processed. Field name is misleading — when inprogress equals total, the job is done. |
total | integer | Total rows submitted. |
status | string | Job lifecycle state. "COMPLETED" is the terminal success state. Other observed values: PENDING, PROCESSING, FAILED. |
created_time | string (ISO 8601) | When the job was accepted. |
log_vswp | array | Per-row results. May be populated incrementally during processing; definitive only when status is "COMPLETED". |
log_vswp[].response_time | string | DJP round-trip time in seconds (e.g. "0.47" = 470ms), formatted as decimal string. |
Known quirks. • The submit response calls the identifier job_id; the status response calls the same value job_vswp_id. They refer to the same UUID. • The inprogress field is misleadingly named — it counts rows already processed, not rows currently being processed. • log_vswp may be populated incrementally during processing; treat it as definitive only when status === "COMPLETED".
5.3.3 Step 3 — Download the result
GET /v1/vswp/{id}/export
Returns the bulk validation result as a CSV file. Only call this when the job's data.status is "COMPLETED".
Response headers
| Header | Value |
|---|---|
Content-Type | text/csv; charset=utf-8 |
Content-Disposition | attachment; filename="VSWP-2026" |
CSV columns (in order)
| Column | Description |
|---|---|
NPWP | The identifier looked up |
Tujuan | Echoes the tujuan value from the input |
Status | Reserved — currently always empty in observed exports |
Nama | Taxpayer name (empty if not found) |
Alamat | Registered address (empty if not found) |
Status WP | "VALID" if found, empty if not |
Status SPT | "VALID" if found, empty if not |
Response Time(ms) | DJP round-trip time. Column header says milliseconds but values are seconds. |
Example CSV output
"NPWP","Tujuan","Status","Nama","Alamat","Status WP","Status SPT","Response Time(ms)"
"3201234567890000","Validasi NPWP",,"Budi Santoso","Jalan Contoh No. 1, Jakarta
12345","VALID","VALID","0.47"
"3301234567890000","Validasi NPWP",,"Siti Aminah","Jalan Mawar No. 5, Surabaya
60111","VALID","VALID","0.45"Quirks to handle in client code. • Filename pattern is
VSWP-2026— no.csvextension, and the value reflects the year, not the job_id. Append.csvwhen persisting the file programmatically. • TheStatuscolumn (betweenTujuanandNama) is always empty. Treat as reserved. • Column header readsResponse Time(ms)but values are seconds (e.g."0.47"means 470ms).
5.4 Choosing between single and bulk
| Use case | Endpoint to use |
|---|---|
| Inline validation during data entry | POST /v2/vswp |
| Fewer than 50 lookups in a workflow | POST /v2/vswp (loop client-side) |
| Periodic batch screening (counterparty master) | POST /v1/vswp/bulking |
| One-off audit of a large taxpayer list | POST /v1/vswp/bulking |
For loops of single lookups, traffic is dominated by cache hits after the first pass — there is no meaningful speed advantage to switching to bulk for small sets. Bulk is preferred when the input set is large enough that the polling overhead is amortised across many rows, or when the input arrives as a file and CSV upload is the natural shape.
5.5 Error handling reference
The table below maps common situations to the response the client will observe.
| Situation | What the client sees |
|---|---|
| NPWP exists and is valid | HTTP 200, data.status = "1", data.result present |
| NPWP not found at DJP | HTTP 200, data.status = "0", message in Bahasa Indonesia |
| NPWP format invalid | Same as "not found" — DJP returns the same message |
| Authentication failure | HTTP 401 |
| NPWP header missing or not registered | HTTP 403 |
| Upstream DJP timeout | HTTP 502 / 504. Safe to retry with exponential backoff. |
| Bulk job: unknown job_id | HTTP 404 |
| Bulk upload too large | HTTP 413 |