1. Getting Started
This guide leads you through the steps to send your first call using the V5 Java API client.
Quick Start (60 Seconds)
3 Requirements
| Item | Value | Source |
|---|---|---|
| Server Address | http://<server-ip>:80 (TLS: https://<server-ip>:443) | REST API endpoint. This is the same address as the web console. |
| Account ID | Example: api | User account for API calls |
| Token | UUID format | Issued for the account via Console Security Management → API Authentication Token (/token/index) → Security Settings · Security Management |
With these three values, you can make your first call using the single block below.
import java.util.List;
import plantpulse.api.v5.APIClient_V5;
import plantpulse.api.v5.dto.response.SiteResponseV5;
try (APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api", "<issued-token>", false)) {
client.connect(); // 인증
System.out.println(client.system().ping().isPing()); // → true
for (SiteResponseV5 s : client.site().list()) // 사이트 목록
System.out.println(s.getSite_id() + " — " + s.getSite_name());
}
If this block outputs true and the site list, you are ready to go. Sections 1.1 to 1.7 below provide detailed explanations for each step.
1.1 Adding Dependencies
Add the JAR file to your classpath.
# 빌드 (Gradle + Java 21)
cd plantpulse-api
./gradlew build
The artifact is created in target/.
| File | Purpose |
|---|---|
target/plantpulse-api.jar | For integration into existing projects along with dependencies |
1.2 Creating the Client
Pass options directly to the APIClient_V5 constructor.
import plantpulse.api.v5.APIClient_V5;
APIClient_V5 client = new APIClient_V5(
"HTTPS", // 프로토콜: "HTTP" 또는 "HTTPS"
"100.68.69.41", // host
443, // port (REST API: 80=HTTP, 443=HTTPS)
"api", // user_id
"19ba7a54-1132-49f2-967e-3c6f5cd989a0", // token (api_key 발급용)
false); // debug
client.connect(); // 인증 + HTTP 클라이언트 초기화
// ... API 호출 ...
client.close(); // 종료
Constructor Parameters
| Parameter | Type | Description |
|---|---|---|
protocol | String | "HTTP" or "HTTPS" |
host | String | Server host or IP |
port | int | Server port |
user_id | String | Authentication account ID |
token | String | Issued token (UUID format) |
debug | boolean | HTTP request/response debug logs |
Authentication Flow: When calling
connect(), an api_key is issued internally usinguser_id+token, and this key is automatically included in the header for all subsequent calls. The user does not need to handle this manually.
1.3 First API Call — Ping & Site List
import java.util.List;
import plantpulse.api.v5.APIClient_V5;
import plantpulse.api.v5.dto.response.SiteResponseV5;
import plantpulse.api.v5.dto.response.SystemPingResponseV5;
public class FirstCall {
public static void main(String[] args) throws Exception {
try (APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api",
"19ba7a54-1132-49f2-967e-3c6f5cd989a0", false)) {
client.connect();
// 1) 서버 헬스체크
SystemPingResponseV5 ping = client.system().ping();
System.out.println("Server alive: " + ping.isPing()
+ " (v" + ping.getVersion() + ")");
// 2) 사이트 목록 (typed DTO 리스트)
List<SiteResponseV5> sites = client.site().list();
for (SiteResponseV5 s : sites) {
System.out.println(s.getSite_id() + " — " + s.getSite_name());
}
}
}
}
Execution Result:
Server alive: true (v5.0)
SITE_000001 — 대전 1공장
SITE_000002 — 천안 2공장
1.4 try-with-resources Pattern
APIClient_V5 implements AutoCloseable. The use of try-with-resources is recommended.
try (APIClient_V5 client = new APIClient_V5(proto, host, port, user, token, false)) {
client.connect();
// ... API 호출 ...
}
// close() 자동 호출 — HTTP 커넥션 정리
1.5 Overview of 13 Services
Immediately after connect(), you can access all domains using the service methods below (lazy initialization).
client.system() // 헬스체크
client.site() // 사이트(공장)
client.customer() // 고객
client.employee() // 직원
client.product() // 제품
client.asset() // 자산 계층 (Area → Line → Equipment)
client.opc() // OPC 데이터 채널
client.tag() // 태그(데이터 포인트)
client.alarm() // 알람
client.order() // 작업지시
client.calendar() // 일정
client.path() // 자산 경로
client.flow() // Flow / Flow Node
1.6 V5 Method Signature Standard Pattern
All domain services follow a consistent method pattern. The usage is identical; only the domain name differs.
| Pattern | Return Type | Return Value on Failure | Description |
|---|---|---|---|
create(req) | *ResponseV5 | null | Registration |
update(id, req) | *ResponseV5 | null | Full Update |
delete(id) | boolean | false | Deletion |
get(id) | *ResponseV5 | null | Single Inquiry |
list() | List<*ResponseV5> | Empty List | Full List |
exists(id) | boolean | false | Existence Check |
count() | long | 0 | Count |
⚠️ Exceptions are not thrown. Communication errors or server ERROR responses are returned as the safe default values shown in the table above. Check the logs or
BaseServiceV5.getErrorCode(env)for the cause of the error. For more details, refer to Response Format and Error Handling.
1.7 Debug Mode
Setting the last argument of the constructor to true will print HTTP requests and responses to the console.
APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api", TOKEN, true); // debug=true
Example Output:
[V5] GET https://server/api/v5/site headers={api_key=ab****cd}
[V5] response: 200 {"_status":"OK","data":[{"site_id":"SITE_000001",...}]}
1.8 When Authentication Fails — 503 is not "Wrong Key"
connect() exchanges a token with POST /api/v5/auth for api_key. Success is not determined by HTTP 200 — it is a success only if meta.status is "OK" and data.api_key is not empty. The second condition exists because there are actual paths where token validation passes but key issuance fails (in which case the server returns 500).
curl -s -X POST "http://<server>/api/v5/auth" \
-H "Content-Type: application/json; charset=UTF-8" \
-d '{"token":"<issued-token>"}'
# 200: {"data":{"api_key":"..."},"meta":{"status":"OK"},"errors":null}
| Response | Code | Meaning | What to fix |
|---|---|---|---|
| 400 | E1001 | token is missing or empty | Request body |
| 422 | E1002 | Body is not JSON | Request body |
| 401 | E1100 | Wrong token | Credentials |
| 401 | E1102 | Token expired | Recovered by re-issuance |
| 401 | E1103 | Token revoked | Same token cannot be recovered — obtain a new one |
| 429 | E1101 | Accumulated failures from the same IP | Wait for Retry-After, then retry after fixing the value |
| 500 | E5000 | Token is correct, but api_key issuance failed | Server-side — not a credential issue |
| 503 | E5500 | «No determination possible» due to inability to reach token store | Server-side — not a credential issue |
The server does not issue a 401 when it cannot reach the token store (PostgreSQL). 401 is a claim that «your credentials are wrong», and at that moment, the server does not know if the token is good or bad. The problem is that the caller has no way to distinguish between the two.
This actually happened — on 2026-09-07, nightly e2e reported «22/22 failed, E1100 Token authentication failed» for eight days, but the real reason in the platform logs was Connection to plantpulse-datalake:5432 refused. A PostgreSQL failure wore the face of a credential error for eight days. Now, the system traces the cause chain to the storage exception (SQLException · socket family) and responds with 503 E5500.
For the same reason, 503 is not counted as a failure. If it were, a DB failure would have locked out healthy callers with 429 — layering a lock on top of a failure.
The Java client returns this distinction exactly as an exception message. Determine where to fix based on the message.
| Message | Meaning |
|---|---|
V5 connect: /api/v5/auth call failed — … | Request did not even reach the server (Address · Port · Firewall) |
V5 connect: auth endpoint unavailable (http=503) — server reached no verdict about the token | Server could not make a determination — do not suspect the token |
V5 connect: authentication failed — … | 401/400 series — fix credentials or request |
V5 connect: api_key issuance failed — response=… | meta.status is OK, but key is empty — server-side |
If authentication failures from the same IP accumulate to engine.api.v5.auth.bruteforce.ip_limit (default 30) times, it is locked with 429 for engine.api.v5.auth.bruteforce.window.minutes (default 15 minutes). This can be disabled via engine.api.v5.auth.bruteforce.enabled=false, but doing so leaves the system vulnerable to token brute-force attacks. Requests where the body is not JSON are not counted as credential attempts.
Next Steps
- Domain ID Rules — Please read this next. ID prefix validation is enforced.
- Response Format and Error Handling — Error code mapping and safe handling patterns
- Site Service — Creating initial master data