PlantPulse API의 REST 엔드포인트와 클라이언트 메서드 매핑입니다. 베이스 경로는 /api/v5 입니다.
인증: APIClient_V5.connect() 호출 시 자동으로 api_key가 발급·관리되므로, 사용자가 직접 호출해야 하는 인증 엔드포인트는 없습니다.
17.1 System
| HTTP | 엔드포인트 | 메서드 |
|---|
| GET | /api/v5/ping | client.system().ping() |
17.2 ID 발급
| 메서드 | 경로 | 설명 |
|---|
| POST | /api/v5/domain-ids | 도메인 ID 를 미리 받습니다(클라이언트 메서드 없음) — ID 규칙 |
17.3 Site (6개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/site | client.site().create(req) |
| PUT | /api/v5/site/{id} | client.site().update(id, req) |
| DELETE | /api/v5/site/{id} | client.site().delete(id) |
| GET | /api/v5/site/{id} | client.site().get(id) |
| GET | /api/v5/site | client.site().list() |
| GET | /api/v5/site/{id}/exists | client.site().exists(id) |
17.4 OPC (10개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/opc | client.opc().create(req) |
| PUT | /api/v5/opc/{id} | client.opc().update(id, req) |
| DELETE | /api/v5/opc/{id} | client.opc().delete(id) |
| GET | /api/v5/opc/{id} | client.opc().get(id) |
| GET | /api/v5/opc | client.opc().list() |
| GET | /api/v5/opc?site_id={id} | client.opc().listBySite(siteId) |
| GET | /api/v5/opc?opc_source_type={type} | client.opc().listByType(sourceType) |
| GET | /api/v5/opc/{id}/exists | client.opc().exists(id) |
| GET | /api/v5/opc/count | client.opc().count() |
| GET | /api/v5/opc/count?site_id={id} | client.opc().countBySite(siteId) |
17.5 Asset (6개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/asset | client.asset().create(req) |
| PUT | /api/v5/asset/{id} | client.asset().update(id, req) |
| DELETE | /api/v5/asset/{id} | client.asset().delete(id) |
| GET | /api/v5/asset/{id} | client.asset().get(id) |
| GET | /api/v5/asset | client.asset().list() |
| GET | /api/v5/asset/{id}/exists | client.asset().exists(id) |
관계 온톨로지 (4개)
계층(부모–자식)과 별개의 방향성 관계입니다. 「이 설비가 멈추면 어디까지 영향을 받나」를 묻는 데 씁니다.
| HTTP | 엔드포인트 | 하는 일 |
|---|
| POST | /api/v5/assets/{asset_id}/relations | 관계 등록 — 본문 {site_id, to_entity_type, to_entity_id, relation_type, description?} → 201 |
| GET | /api/v5/assets/{asset_id}/relations?type= | 직접 관계 목록(들어오는 것 · 나가는 것) |
| DELETE | /api/v5/relations/{relation_id} | 관계 삭제 → 204 |
| GET | /api/v5/ontology/graph/{entity_id}?relation=&direction=DOWN&depth=2 | 그래프 탐색(BFS) |
| 관계 | 뜻 | 방향 |
|---|
FEEDS | 공정 흐름 | 자산 → 자산 |
DEPENDS_ON | 유틸리티 의존(전력 · 에어 · 냉각) | 자산 → 자산 |
PRODUCES | 생산 산출 | 자산 → 제품 |
direction 은 UP · DOWN · BOTH(기본 DOWN), depth 는 1~5(기본 2)입니다.
- 자기 자신을 가리키는 관계는 저장되지 않고, 같은 조합의 관계는 한 번만 등록됩니다.
- 등록 · 삭제는 변경이라 ADMIN/API 역할과 감사 기록이 적용됩니다.
- 같은 탐색을 AI 어시스턴트가 부르는 것이 MCP 의
trace_asset_relations 입니다.
QR 라벨
| HTTP | 엔드포인트 | 하는 일 |
|---|
| GET | /api/v5/asset/qr/{token} | 라벨 토큰의 설비. 토큰이 아니거나 재발급된 옛 토큰이면 404 |
라벨에 담긴 주소는 GET /api/v5/asset/{id} 응답의 qr_payload 입니다. 이 호출은 토큰을 만들지 않으므로, 토큰이 아직 없거나 PP_UI_CONSOLE_URL 이 없으면 "" 입니다. 로그인 없는 공개 페이지는 V5 가 아니라 /qr/{token} 입니다 — QR 라벨과 공개 페이지.
17.6 Tag (23개)
CRUD + 목록
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/tag | client.tag().create(req) |
| PUT | /api/v5/tag/{id} | client.tag().update(id, req) |
| DELETE | /api/v5/tag/{id} | client.tag().delete(id) |
| GET | /api/v5/tag/{id} | client.tag().get(id) |
| GET | /api/v5/tag/{id}/exists | client.tag().exists(id) |
| GET | /api/v5/tag | client.tag().list() |
| GET | /api/v5/tag?site_id={id} | client.tag().listBySite(siteId) |
| GET | /api/v5/tag?opc_id={id} | client.tag().listByOpc(opcId) |
| GET | /api/v5/tag?asset_id={id} | client.tag().listByAsset(assetId) |
| GET | /api/v5/tag/count | client.tag().count() |
| GET | /api/v5/tag/count?site_id={id} | client.tag().countBySite(siteId) |
| GET | /api/v5/tag/count?opc_id={id} | client.tag().countByOpc(opcId) |
| GET | /api/v5/tag/count?asset_id={id} | client.tag().countByAsset(assetId) |
PATCH (10개 — 탭별 부분 수정)
| HTTP | 엔드포인트 | 메서드 |
|---|
| PATCH | /api/v5/tag/{id}/basic | patchBasic(id, req) |
| PATCH | /api/v5/tag/{id}/alarm | patchAlarm(id, req) |
| PATCH | /api/v5/tag/{id}/metadata | patchMetadata(id, req) |
| PATCH | /api/v5/tag/{id}/calculation | patchCalculation(id, req) |
| PATCH | /api/v5/tag/{id}/sampling | patchSampling(id, req) |
| PATCH | /api/v5/tag/{id}/aggregation | patchAggregation(id, req) |
| PATCH | /api/v5/tag/{id}/ai | patchAi(id, req) |
| PATCH | /api/v5/tag/{id}/publish | patchPublish(id, req) |
| PATCH | /api/v5/tag/{id}/attribute | patchAttribute(id, req) |
| PATCH | /api/v5/tag/{id}/link | patchLink(id, req) |
17.7 Alarm (3개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| GET | /api/v5/alarm/{seq} | client.alarm().get(seq) |
| GET | /api/v5/alarm?limit={n} | client.alarm().list(limit) |
| GET | /api/v5/alarm/performance?scope_type=&scope_id= | 알람 시스템 성능(클라이언트 메서드 없음) |
/alarm/performance — scope_type 은 SITE · AREA · LINE, scope_id 는 사이트 ID 또는 에셋 ID 이고 둘 다 필수입니다. 기간은 days(1~31, 기본 7) 또는 from + to(둘이 함께, 31일까지)이고, from/to 가 days 보다 우선합니다. 알린 발생만 세고, 숨김 · 억제 중에 열린 것은 suppression 에 따로 나옵니다. 범위 · 기간이 틀리면 400 입니다. 같은 값을 MCP get_alarm_performance 가 돌려줍니다.
17.8 Order (11개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/order | client.order().create(req) |
| PUT | /api/v5/order/{id} | client.order().update(id, req) |
| DELETE | /api/v5/order/{id} | client.order().delete(id) |
| GET | /api/v5/order/{id} | client.order().get(id) |
| GET | /api/v5/order | client.order().list() |
| GET | /api/v5/order/{id}/exists | client.order().exists(id) |
| POST | /api/v5/order/{id}/start | client.order().start(id) |
| POST | /api/v5/order/{id}/end | client.order().end(id) |
| POST | /api/v5/order/{id}/pause | client.order().pause(id) |
| POST | /api/v5/order/{id}/resume | client.order().resume(id) |
| POST | /api/v5/order/{id}/abort | client.order().abort(id) |
17.8.1 정비 오더
설비 정비의 호출 · 수리 · 예방정비 작업입니다(ISA-95 maintenance work order). 생산 워크오더(/order)와 다른 객체이고, 클라이언트 메서드 없이 REST 로 부릅니다.
| HTTP | 엔드포인트 | 하는 일 |
|---|
| GET | /api/v5/maintenance-orders | 목록. 거르기 scope+scope_id(asset · line · area · site) · status_code · open · maintenance_kind_code · assignee_employee_id · failure_mode_code · maintainable_item_code · from/to · period_of · overdue · external_system · external_id. 쪽 page · limit(기본 50, 최대 500) · sort · order |
| GET | /api/v5/asset/{asset_id}/maintenance-orders | 설비 하나의 목록 |
| POST | /api/v5/asset/{asset_id}/maintenance-orders | 정비 호출 추가 |
| GET | /api/v5/maintenance-orders/{maintenance_order_id} | 한 건 |
| PATCH | /api/v5/maintenance-orders/{maintenance_order_id} | 내용 고치기 |
| POST | /api/v5/maintenance-orders/{maintenance_order_id}/transition | 상태 옮기기(받음 · 시작 · 완료 · 취소). 본문 status_code · version, 취소는 cancel_reason_code |
| GET | /api/v5/maintenance-orders/{maintenance_order_id}/revisions | 판 이력 |
| GET | /api/v5/maintenance-orders/summary | 범위 · 기간의 정비 요약 |
| GET | /api/v5/maintenance-orders/options | 넣을 수 있는 종류 · 상태 · 코드 |
| GET | /api/v5/maintenance-orders/board | 범위의 정비 현황판 |
| GET | /api/v5/maintenance-orders/changes | CMMS 동기화용 변경 피드(커서) |
| GET · PUT | /api/v5/maintenance-orders/by-external/{system}/{external_id} | 외부(CMMS) 번호로 찾기 · 멱등 쓰기 |
| GET · PUT | /api/v5/maintenance-orders/by-external?system=&external_id= | 같은 일. 번호에 / 가 있을 때 |
| POST · GET | /api/v5/maintenance-orders/{maintenance_order_id}/attachments | 사진 올리기 · 목록 |
| GET | /api/v5/maintenance-orders/{maintenance_order_id}/attachments/{maintenance_attachment_seq}/content | 사진 내용 |
정비 오더 칸
칸 이름은 응답 · 요청 본문 · 목록 질의가 같습니다.
| 칸 | 타입 | 뜻 |
|---|
maintenance_order_id | 문자 | MAINTENANCE_ORDER_000001. 옛 행은 숫자 문자열("12") |
maintenance_kind_code | 문자 | 정비 종류(CORRECTIVE …) |
status_code | 문자 | 상태(REQUESTED · ACCEPTED · IN_PROGRESS · COMPLETED · CANCELLED) |
cancel_reason_code | 문자 | 취소 사유 |
failure_record_seq | 숫자 | 연결된 고장 기록 |
maintenance_plan_id · maintenance_plan_name | 문자 | 예방정비 계획. MAINTENANCE_PLAN_000001 또는 옛 숫자 문자열 |
failure_mode_code · failure_mechanism_code · failure_cause_code · maintainable_item_code | 문자 | ISO 14224 코드. 표시 이름은 _code 대신 _name |
cause_code | 문자 | 원인 사전 코드(알람과 같은 사전) |
checklist_results[].maintenance_attachment_seq | 숫자 | 점검 항목의 사진 |
CMMS 웹훅
설정 키 PP_MAINTENANCE_WEBHOOK_URL 에 주소를 넣으면, 정비 오더의 상태가 바뀔 때마다 JSON 을 한 번 POST 합니다(호출 · 받음 · 시작 · 완료 · 취소). 내용만 고칠 때는 보내지 않고, 비워 두면 꺼집니다. 실패하면 진단 diagnostic.maintenance.webhook_failed 가 켜지고 다음 성공에 꺼지며, 다시 보내지는 않습니다.
| 키 | 값 |
|---|
text | 설치 언어의 한 줄 문장 |
event | maintenance.requested · maintenance.accepted · maintenance.in_progress · maintenance.completed · maintenance.cancelled |
maintenance_order_id | 정비 오더 ID(문자) |
asset_id · asset_name | 설비 |
maintenance_kind_code · status_code | 종류 · 상태 |
description · failure_mode_code | 설명 · 고장 모드 |
requested_by · accepted_by · assignee_employee_id | 사람 |
cancel_reason_code | 취소 사유 |
external_system · external_id · owner | 외부 번호와 주인 |
anomaly_found · checklist_results | 점검 이상 여부와 답(item_id · checked · value · maintenance_attachment_seq · out_of_range) |
maintenance_plan_id · plan_due_at | 예방정비 계획 |
at · version | 그 상태가 된 시각(epoch ms) · 판 |
값을 모르는 키도 빠지지 않고 null 로 실립니다.
17.9 Calendar (6개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/calendar | client.calendar().create(req) |
| PUT | /api/v5/calendar/{id} | client.calendar().update(id, req) |
| DELETE | /api/v5/calendar/{id} | client.calendar().delete(id) |
| GET | /api/v5/calendar/{id} | client.calendar().get(id) |
| GET | /api/v5/calendar | client.calendar().list() |
| GET | /api/v5/calendar/search?from={iso}&to={iso} | client.calendar().search(from, to) |
17.10 Customer (8개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/customer | client.customer().create(req) |
| PUT | /api/v5/customer/{id} | client.customer().update(id, req) |
| DELETE | /api/v5/customer/{id} | client.customer().delete(id) |
| GET | /api/v5/customer/{id} | client.customer().get(id) |
| GET | /api/v5/customer | client.customer().list() |
| GET | /api/v5/customer?site_id={id} | client.customer().listBySite(siteId) |
| GET | /api/v5/customer/{id}/exists | client.customer().exists(id) |
| GET | /api/v5/customer/count | client.customer().count() |
17.11 Employee (7개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/employee | client.employee().create(req) |
| PUT | /api/v5/employee/{id} | client.employee().update(id, req) |
| DELETE | /api/v5/employee/{id} | client.employee().delete(id) |
| GET | /api/v5/employee/{id} | client.employee().get(id) |
| GET | /api/v5/employee | client.employee().list() |
| GET | /api/v5/employee/{id}/exists | client.employee().exists(id) |
| GET | /api/v5/employee/count | client.employee().count() |
17.12 Product (7개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| POST | /api/v5/product | client.product().create(req) |
| PUT | /api/v5/product/{id} | client.product().update(id, req) |
| DELETE | /api/v5/product/{id} | client.product().delete(id) |
| GET | /api/v5/product/{id} | client.product().get(id) |
| GET | /api/v5/product | client.product().list() |
| GET | /api/v5/product/{id}/exists | client.product().exists(id) |
| GET | /api/v5/product/count | client.product().count() |
17.13 Path (2개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| GET | /api/v5/path/asset/{id} | client.path().getByAsset(assetId) |
| GET | /api/v5/path/tag/{id} | client.path().getByTag(tagId) |
17.14 Flow (3개)
| HTTP | 엔드포인트 | 메서드 |
|---|
| GET | /api/v5/flow/{id} | client.flow().get(flowId) |
| GET | /api/v5/flow | client.flow().list() |
| GET | /api/v5/flow/{id}/node | client.flow().listNodes(flowId) |
17.15 통계
아래 수는 plantpulse-api 클라이언트 메서드가 있는 경로만 셉니다.
| 도메인 | 엔드포인트 수 |
|---|
| System | 1 |
| Site | 6 |
| OPC | 10 |
| Asset | 6 |
| Tag | 23 (CRUD 5 + 목록 7 + 카운트 4 + PATCH 10) |
| Alarm | 2 |
| Order | 11 (CRUD 6 + 라이프사이클 5) |
| Calendar | 6 |
| Customer | 8 |
| Employee | 7 |
| Product | 7 |
| Path | 2 |
| Flow | 3 |
| 합계 | 92 (+인증 1) |
17.16 HTTP 메서드 분포
| HTTP | 개수 | 용도 |
|---|
| GET | 56 | 조회 (단건/목록/존재 여부/카운트) |
| POST | 16 | 등록 + Order 라이프사이클 |
| PUT | 10 | 전체 수정 |
| PATCH | 10 | Tag 탭별 부분 수정 |
| DELETE | 10 | 삭제 |
17.17 목록을 끝까지 읽기 — 커서
GET /api/v5/site · /product · /customer · /employee 는 커서로 이어 읽습니다. 쪽 크기 limit 은 기본 100, 상한 1000 이고(더 크면 1000 으로 줄입니다), 첫 호출에는 cursor 를 넣지 않습니다.
curl -H "X-API-Key: $TOKEN" "$BASE/api/v5/site?limit=500"
curl -H "X-API-Key: $TOKEN" "$BASE/api/v5/site?limit=500&cursor=<next_cursor>"
{
"data": [ ],
"meta": {
"status": "OK",
"pagination": { "limit": 500, "total": 1234 },
"cursor": { "next_cursor": "…", "has_more": true, "limit": 500 }
},
"errors": null
}
data 는 이 쪽의 행 배열입니다.
meta.pagination.total 은 같은 필터의 전체 건수입니다.
meta.cursor.has_more 가 false 가 될 때까지 next_cursor 를 그대로 다음 호출의 cursor 로 넘깁니다.
- 커서는 그 목록과 필터에 묶입니다. 다른 목록의 커서나
site_id 를 바꾼 호출에 넣으면 422 E1002 입니다.
- 고객 · 제품 · 직원은 ID 순서, 사이트는 이름 · ID 순서입니다. 읽는 동안 행이 수정돼도 빠지지 않습니다.
Java 클라이언트의 list() 는 cursor 를 넘기지 않으므로 첫 쪽만 돌려줍니다. 끝까지 읽으려면 REST 로 부르세요.
17.18 바뀌었을 때만 받기 — /tag/export 의 ETag
GET /api/v5/tag/export 는 사이트 · 연결 · 플랜트 전체의 태그를 한 번에 냅니다. site_id · opc_id 로 거르고, include=config 면 행마다 설정이 실립니다(태그마다 설정을 부르지 않아도 됩니다). 응답은 data = {tags: [...], count: N} 입니다.
응답의 ETag 를 보관했다가 다음 읽기에 If-None-Match 로 돌려줍니다.
curl -i -H "X-API-Key: $TOKEN" "$BASE/api/v5/tag/export?site_id=SITE_000001&include=config"
curl -i -H "X-API-Key: $TOKEN" -H 'If-None-Match: "<SHA-256>"' \
"$BASE/api/v5/tag/export?site_id=SITE_000001&include=config"
ETag 는 내보내는 data 의 SHA-256 입니다. 이 응답에 보이는 것이 바뀌면 — 태그나 설정의 변경, 태그 추가 · 삭제, 연결이 다른 사이트로 옮겨 간 경우 — 누가 바꿨든 값이 달라집니다. 바뀌지 않았으면 재기동해도, 다른 노드에서 읽어도 같습니다.
- 프록시가 붙인 약한 형식
W/"…" 과 * 도 받습니다.
- 304 는 전송과 파싱을 아낄 뿐 읽기를 아끼지 않습니다. 서버는 값을 계산하려고 행을 전부 읽습니다. 데이터가 필요한 주기보다 자주 부르지 마세요.
KOPENS All rights reserved.