417 lines
13 KiB
Markdown
417 lines
13 KiB
Markdown
# 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 <repository-url>
|
|
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
|