# SoluTax IFS WIT API - Bruno Collection A **Bruno API collection** for testing and interacting with the **SoluTax IFS WIT API** developed by PT Sarana Prima Telematika. This collection provides integration capabilities with Indonesia's tax system (DJP - Direktorat Jenderal Pajak) for electronic withholding tax slips (Bukti Potong). ## Overview | Item | Details | |------|---------| | **API Base URL** | `https://ifswit-solutax-ctas-dev.spt.co.id` | | **Environment** | Development (CTAS-DEV) | | **Authentication** | JWT Token via Basic Auth | | **Tax Types** | PPh 21, PPh A0, PPh A1 | ## Tax Slip Types Supported - **PPh 21** - Employee income tax withholding (monthly/non-final) - **PPh A0** - Permanent employee monthly withholding - **PPh A1** - Permanent employee annual withholding ## Prerequisites - [Bruno API Client](https://www.usebruno.com/) - Download and install - Valid credentials for SoluTax API (username/password) - NPWP (Tax ID) for testing transactions ## Quick Start ### 1. Clone and Open in Bruno ```bash # Clone this repository git clone cd solutax_api # Open in Bruno # File > Open Folder > Select solutax_api directory ``` ### 2. Configure Environment 1. Open Bruno 2. Navigate to **Environments** > **solutax** 3. Configure your credentials: - `username` - Your API username - `password` - Your API password - `passphrase` - Electronic signature passphrase - `npwp` - Your NPWP number - `npwp_pemilik` - Employer NPWP ### 3. Get Authentication Token 1. Select `token.bru` in the collection 2. Click **Send Request** (or press `Ctrl+Enter`) 3. Verify response contains `access_token` 4. Token is automatically stored in environment variable ### 4. Create Your First Tax Slip 1. Select **PPh A0** > **PPh A0 - Pengesahan Baru.bru** 2. Click **Send Request** 3. Note the `nomorBupot` and `idBupot` from response ### 5. Verify Status 1. Select **PPh A0** > **ppha0-status.bru** 2. Click **Send Request** 3. Confirm `statusBupot` is `NORMAL-DONE` ## Project Structure ``` solutax_api/ ├── bruno.json # Bruno collection configuration ├── readme.md # This file ├── agents.md # AI agent documentation ├── spesifikasi.md # Full API specification (Indonesian) ├── token.bru # Authentication token request ├── package-lock.json # Node.js lock file │ ├── environments/ │ ├── solutax.bru # Environment variables template │ ├── solutax.json # Environment configuration │ └── solutax copy.json # Backup environment │ ├── PPh 21/ # PPh 21 (Monthly/Non-Final) │ ├── PPh 21 - Pengesahan Baru.bru │ ├── pph21-edit.bru │ ├── pph21-cancel.bru │ ├── pph21-status.bru │ └── pph21-pdf.bru │ ├── PPh A0/ # PPh A0 (Permanent Employee Monthly) │ ├── PPh A0 - Pengesahan Baru.bru │ ├── ppha0-edit.bru │ ├── ppha0-cancel.bru │ ├── ppha0-status.bru │ └── ppha0-pdf.bru │ ├── PPh A1/ # PPh A1 (Permanent Employee Annual) │ ├── PPh A1 - Pengesahan Baru.bru │ ├── ppha1-edit.bru │ ├── ppha1-cancel.bru │ ├── ppha1-status.bru │ └── ppha1-pdf.bru │ └── sample result/ # Sample API responses ├── token_result_sample.json └── ppha0_new_result_sample.json ``` ## API Endpoints ### Authentication | Endpoint | Method | Description | |----------|--------|-------------| | `/auth/gettoken` | POST | Get JWT access token using Basic Auth | ### PPh 21 (Monthly/Non-Final) | Endpoint | Method | Description | |----------|--------|-------------| | `/ifs/api/wit/bulanan/new` | POST | Create and approve new PPh 21 slip | | `/ifs/api/wit/bulanan/edit` | POST | Replace/modify existing PPh 21 slip | | `/ifs/api/wit/cancel` | POST | Cancel a PPh 21 slip | | `/ifs/api/wit/status` | POST | Check status of PPh 21 slip | | `/ifs/api/wit/pdf` | POST | Download PDF of PPh 21 slip | ### PPh A0 (Permanent Employee Monthly) | Endpoint | Method | Description | |----------|--------|-------------| | `/ifs/api/wit/bulanan/new` | POST | Create and approve new PPh A0 slip | | `/ifs/api/wit/bulanan/edit` | POST | Replace/modify existing PPh A0 slip | | `/ifs/api/wit/cancel` | POST | Cancel a PPh A0 slip | | `/ifs/api/wit/status` | POST | Check status of PPh A0 slip | | `/ifs/api/wit/pdf` | POST | Download PDF of PPh A0 slip | ### PPh A1 (Permanent Employee Annual) | Endpoint | Method | Description | |----------|--------|-------------| | `/ifs/api/wit/tahunan/new` | POST | Create and approve new PPh A1 slip | | `/ifs/api/wit/tahunan/edit` | POST | Replace/modify existing PPh A1 slip | | `/ifs/api/wit/cancel` | POST | Cancel a PPh A1 slip | | `/ifs/api/wit/status` | POST | Check status of PPh A1 slip | | `/ifs/api/wit/pdf` | POST | Download PDF of PPh A1 slip | ## Environment Variables Configure these in **Environments** > **solutax**: | Variable | Description | Required | |----------|-------------|----------| | `accessToken` | JWT authentication token | Yes (auto-generated) | | `idpel` | Customer ID | Yes (from token response) | | `requestID` | Unique request GUID | Yes (auto-generated) | | `username` | API username | Yes | | `password` | API password | Yes | | `passphrase` | Electronic signature passphrase | Yes | | `npwp` | Employee NPWP | Yes | | `npwp_pemilik` | Employer NPWP | Yes | | `nomorBupot` | Tax slip number | Yes (from create response) | | `idBupot` | Tax slip ID (UUID) | Yes (from create response) | ## Request/Response Patterns ### Request Structure All requests follow a consistent pattern: ```json { "idPel": 12345, "requestID": "uuid-string", "dataBpA0": { ... } } ``` ### Response Structure ```json { "kodestatus": 200, "keterangan": "Success", "data": { ... }, "idPel": 12345 } ``` ### Common Status Codes | Code | Meaning | |------|---------| | 200 | Success | | 401 | Unauthorized (invalid/expired token) | | 500 | Server error (e.g., invalid User ID) | ### Slip Status Values | Status | Meaning | |--------|---------| | `NORMAL-DONE` | Original slip approved | | `AMENDED` | Slip was replaced/modified | | `CANCELLED-Done` | Slip was cancelled | ## Testing Workflow ### Complete Workflow Example ``` 1. Get Token └─> token.bru → accessToken set automatically 2. Create Slip └─> PPh A0/PPh A0 - Pengesahan Baru.bru → nomorBupot and idBupot returned 3. Verify Status └─> PPh A0/ppha0-status.bru → statusBupot = "NORMAL-DONE" 4. Download PDF (optional) └─> PPh A0/ppha0-pdf.bru → Base64 PDF in response 5. Modify Slip (if needed) └─> PPh A0/ppha0-edit.bru → New nomorBupot assigned 6. Cancel Slip (if needed) └─> PPh A0/ppha0-cancel.bru → statusBupot = "CANCELLED-Done" ``` ## Happy Flow Diagram ```mermaid flowchart TD Start([Start]) --> Auth[Get Authentication Token] Auth -->|POST /auth/gettoken| TokenAPI[Token API] TokenAPI -->|Returns: access_token, idpel| TokenOK{Token Received?} TokenOK -->|Yes| Create[Create Tax Slip] TokenOK -->|No| Error1[Check Credentials] Error1 --> Auth Create --> CreateAPI{Choose Tax Slip Type} CreateAPI -->|PPh 21| P21[POST /ifs/api/wit/bulanan/new] CreateAPI -->|PPh A0| PA0[POST /ifs/api/wit/bulanan/new] CreateAPI -->|PPh A1| PA1[POST /ifs/api/wit/tahunan/new] P21 -->|Request: monthlyIncome, dataBp21| CreateSuccess{Success?} PA0 -->|Request: monthlyIncome, dataBpA0| CreateSuccess PA1 -->|Request: yearlyIncome, dataBpA1| CreateSuccess CreateSuccess -->|Yes: status=1| Return1[Returns: nomorBupot, idBupot] CreateSuccess -->|No: status=0| Error2[Handle Error] Error2 --> Create Return1 --> Status[Check Tax Slip Status] Status --> StatusAPI{Choose Tax Slip Type} StatusAPI -->|PPh 21| S21[POST /ifs/api/wit/status] StatusAPI -->|PPh A0| SA0[POST /ifs/api/wit/status] StatusAPI -->|PPh A1| SA1[POST /ifs/api/wit/status] S21 -->|Request: taxSlipVerification| StatusOK{Status Received?} SA0 -->|Request: taxSlipVerification| StatusOK SA1 -->|Request: taxSlipVerification| StatusOK StatusOK -->|statusBupot=NORMAL-DONE| Decision{What's Next?} StatusOK -->|statusBupot=AMENDED| Decision StatusOK -->|statusBupot=CANCELLED-Done| End1([End]) StatusOK -->|Error| Error3[Handle Error] Error3 --> Status Decision -->|Download PDF| PDF[Download PDF] Decision -->|Modify Slip| Edit[Edit Tax Slip] Decision -->|Cancel Slip| Cancel[Cancel Tax Slip] Decision -->|Done| End2([End]) PDF --> PDFAPI{Choose Tax Slip Type} PDFAPI -->|PPh 21| PF21[POST /ifs/api/wit/pdf] PDFAPI -->|PPh A0| PFA0[POST /ifs/api/wit/pdf] PDFAPI -->|PPh A1| PFA1[POST /ifs/api/wit/pdf] PF21 -->|Returns: Base64 PDF| PDFOK{Downloaded?} PFA0 -->|Returns: Base64 PDF| PDFOK PFA1 -->|Returns: Base64 PDF| PDFOK PDFOK -->|Yes| End3([End]) PDFOK -->|No| Error4[Handle Error] Error4 --> PDF Edit --> EditAPI{Choose Tax Slip Type} EditAPI -->|PPh 21| E21[POST /ifs/api/wit/bulanan/edit] EditAPI -->|PPh A0| EA0[POST /ifs/api/wit/bulanan/edit] EditAPI -->|PPh A1| EA1[POST /ifs/api/wit/tahunan/edit] E21 -->|Request: monthlyIncome, nomorBupot, idBupot| EditSuccess{Success?} EA0 -->|Request: monthlyIncome, nomorBupot, idBupot| EditSuccess EA1 -->|Request: yearlyIncome, nomorBupot, idBupot| EditSuccess EditSuccess -->|Yes: status=1| Return2[Returns: new nomorBupot, new idBupot] EditSuccess -->|No: status=0| Error5[Handle Error] Error5 --> Edit Return2 --> Status2[Check Status Again] Status2 --> Status Cancel --> CancelAPI{Choose Tax Slip Type} CancelAPI -->|PPh 21| C21[POST /ifs/api/wit/cancel] CancelAPI -->|PPh A0| CA0[POST /ifs/api/wit/cancel] CancelAPI -->|PPh A1| CA1[POST /ifs/api/wit/cancel] C21 -->|Request: taxSlipCancel| CancelSuccess{Success?} CA0 -->|Request: taxSlipCancel| CancelSuccess CA1 -->|Request: taxSlipCancel| CancelSuccess CancelSuccess -->|Yes: status=1| Return3[Returns: status=1] CancelSuccess -->|No: status=0| Error6[Handle Error] Error6 --> Cancel Return3 --> Status3[Verify Cancellation] Status3 --> Status style Start fill:#e1f5fe style Auth fill:#e1f5fe style Create fill:#fff3e0 style Status fill:#e8f5e9 style PDF fill:#f3e5f5 style Edit fill:#fff8e1 style Cancel fill:#ffebee style End1 fill:#c8e6c9 style End2 fill:#c8e6c9 style End3 fill:#c8e6c9 style Error1 fill:#ffcdd2 style Error2 fill:#ffcdd2 style Error3 fill:#ffcdd2 style Error4 fill:#ffcdd2 style Error5 fill:#ffcdd2 style Error6 fill:#ffcdd2 ``` ### Quick Reference: Happy Flow Steps | Step | Action | Endpoint | Returns | |------|--------|----------|---------| | 1 | Get Token | `POST /auth/gettoken` | `access_token`, `idpel` | | 2 | Create Slip | `POST /ifs/api/wit/bulanan/new` or `/tahunan/new` | `nomorBupot`, `idBupot` | | 3 | Check Status | `POST /ifs/api/wit/status` | `statusBupot` | | 4a | Download PDF | `POST /ifs/api/wit/pdf` | Base64 PDF | | 4b | Edit Slip | `POST /ifs/api/wit/bulanan/edit` or `/tahunan/edit` | New `nomorBupot` | | 4c | Cancel Slip | `POST /ifs/api/wit/cancel` | Success confirmation | ### Status Flow ```mermaid stateDiagram-v2 [*] --> NORMAL_DONE: Pengesahan (New) NORMAL_DONE --> AMENDED: Penggantian (Edit) AMENDED --> AMENDED: Penggantian Lagi NORMAL_DONE --> CANCELLED_DONE: Pembatalan (Cancel) AMENDED --> CANCELLED_DONE: Pembatalan (Cancel) CANCELLED_DONE --> [*] ``` ## Important Notes 1. **Language**: All API documentation and field names are in Indonesian (Bahasa Indonesia) 2. **Environment**: This is a development/DEV environment (CTAS-DEV) - do not use for production 3. **Token Expiration**: Monitor `expires_in` field; tokens expire and require renewal 4. **NPWP Validation**: Tax ID numbers (NPWP) are validated on all endpoints 5. **Electronic Signature**: Passphrase required for penandatangan (signatory) on create/edit/cancel operations 6. **Pre-request Scripts**: Some files auto-generate UUIDs for `requestID` using JavaScript 7. **Post-response Scripts**: Some files extract and store response values as environment variables ## Documentation References - [spesifikasi.md](spesifikasi.md) - Complete API specification (Indonesian) - [agents.md](agents.md) - AI agent documentation - [Official Bruno Docs](https://docs.usebruno.com/) - [SoluTax API](https://ifswit-solutax-ctas-dev.spt.co.id) - API base URL ## Troubleshooting ### Token Issues - **401 Unauthorized**: Token expired or invalid → Get new token via `token.bru` - **500 Server Error**: Check username/password credentials ### Slip Creation Issues - **Missing Fields**: Ensure all required fields are filled in the request body - **NPWP Invalid**: Verify NPWP format (15 digits with dots) - **Signature Error**: Check passphrase is correct ### PDF Download Issues - **Empty Response**: Ensure slip status is `NORMAL-DONE` before downloading - **Invalid Base64**: Response data field contains Base64-encoded PDF ## License Copyright © 2026 PT Sarana Prima Telematika. All rights reserved. ## Contact **Developer**: PT Sarana Prima Telematika **Version**: 1.0 **Year**: 2026