VSWP — Validasi Status Wajib Pajak

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.

MethodPathFungsi
POST/v2/vswpSingle taxpayer lookup
POST/v1/vswp/bulkingSubmit a bulk lookup job
GET/v1/vswp/{id}Poll status of a bulk job
GET/v1/vswp/{id}/exportDownload 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

MethodPathPurpose
POST/v2/vswpSingle taxpayer lookup
POST/v1/vswp/bulkingSubmit a bulk lookup job
GET/v1/vswp/{id}Poll status of a bulk job
GET/v1/vswp/{id}/exportDownload 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

HeaderRequiredDescription
AuthorizationYesHTTP Basic Auth (see section 2.2)
npwpYesThe organisation NPWP this call acts on behalf of (see section 2.3)
Content-TypeYesapplication/json

Request body

FieldTypeRequiredDescription
npwpstringYesThe identifier to look up. Accepts 15-digit legacy NPWP, 16-digit harmonised NPWP, or 16-digit NIK. Not format-validated by the endpoint.
tujuanstringYesBusiness 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

FieldTypeDescription
statusstring"1" for success (result present), "0" for failure (result absent)
statusMessagestringHuman-readable outcome. "Success" on success; DJP error message on failure
data.result.npwpstringThe identifier as DJP records it
data.result.namastringTaxpayer name (individual or entity)
data.result.alamatstringRegistered address
data.result.statusWpstringTaxpayer status. "VALID" indicates active
data.result.statusSptstringSPT filing status. "VALID" indicates current on filings
uuidstringServer-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

FieldTypeRequiredDescription
Content-TypeheaderYesmultipart/form-data
fileform field (binary)YesCSV 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 NPWP

Notes on the CSV format:

  • Header row is required — first row must contain the column names NPWP and Tujuan (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 NPWP or Konfirmasi 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

ParameterDescription
idThe 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

FieldTypeDescription
job_vswp_idstring (uuid)The job identifier. Same value as job_id from submit response.
inprogressintegerRows already processed. Field name is misleading — when inprogress equals total, the job is done.
totalintegerTotal rows submitted.
statusstringJob lifecycle state. "COMPLETED" is the terminal success state. Other observed values: PENDING, PROCESSING, FAILED.
created_timestring (ISO 8601)When the job was accepted.
log_vswparrayPer-row results. May be populated incrementally during processing; definitive only when status is "COMPLETED".
log_vswp[].response_timestringDJP 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

HeaderValue
Content-Typetext/csv; charset=utf-8
Content-Dispositionattachment; filename="VSWP-2026"

CSV columns (in order)

ColumnDescription
NPWPThe identifier looked up
TujuanEchoes the tujuan value from the input
StatusReserved — currently always empty in observed exports
NamaTaxpayer name (empty if not found)
AlamatRegistered 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 .csv extension, and the value reflects the year, not the job_id. Append .csv when persisting the file programmatically. • The Status column (between Tujuan and Nama) is always empty. Treat as reserved. • Column header reads Response Time(ms) but values are seconds (e.g. "0.47" means 470ms).

5.4 Choosing between single and bulk

Use caseEndpoint to use
Inline validation during data entryPOST /v2/vswp
Fewer than 50 lookups in a workflowPOST /v2/vswp (loop client-side)
Periodic batch screening (counterparty master)POST /v1/vswp/bulking
One-off audit of a large taxpayer listPOST /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.

SituationWhat the client sees
NPWP exists and is validHTTP 200, data.status = "1", data.result present
NPWP not found at DJPHTTP 200, data.status = "0", message in Bahasa Indonesia
NPWP format invalidSame as "not found" — DJP returns the same message
Authentication failureHTTP 401
NPWP header missing or not registeredHTTP 403
Upstream DJP timeoutHTTP 502 / 504. Safe to retry with exponential backoff.
Bulk job: unknown job_idHTTP 404
Bulk upload too largeHTTP 413