API 레퍼런스
Core API 레퍼런스
Weighter Agent API의 모든 엔드포인트입니다. 기본 URL은 https://api.weighter.shop/agent/v1 이며, 모든 에이전트 엔드포인트는 Authorization: Bearer wtr_ak_… 헤더로 인증합니다. 이 문서는 커밋된 OpenAPI 스냅샷에서 생성됩니다.
agent-v1
Agent API v1 — `Authorization: Bearer wtr_ak_...` 키로 호출하는 계량소 스코프 공개 API. 모든 조회·쓰기는 키에 바인딩된 계량소로 강제 스코프된다.
/agent/v1/me키 메타·바인딩된 계량소 요약
키의 이름·스코프·만료 시각과, 키가 바인딩된 계량소 요약을 반환한다. 유효한 키만 있으면 되고 별도 스코프는 필요 없다.
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/me' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| name | string | 키 이름 |
| scopes | AgentScope[] | |
| expiresAt | string <date-time>| null | 만료 시각(무기한이면 null) |
| station | object | 키에 바인딩된 계량소 요약 |
| id | string <uuid> | |
| name | string | |
| region | string| null | |
| address | string | |
| approvalStatus | enum | 계량소 승인 상태draft · pending · approved · rejected · revoked |
응답 예시
{
"success": true,
"data": {
"name": "string",
"scopes": [
"read:station"
],
"expiresAt": "2026-07-11T09:00:00.000Z",
"station": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"region": "string",
"address": "string",
"approvalStatus": "draft"
}
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수(revoked)되었거나 만료(expired)된 키 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/station바인딩된 계량소 상세
키가 바인딩된 계량소 정보를 요금 규칙(feeRules)·인디케이터 설정(indicatorConfigs)과 함께 반환한다.
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/station' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| ownerId | string <uuid> | |
| name | string | |
| region | string| null | |
| address | string | |
| detailAddress | string| null | |
| lat | number| null | |
| lng | number| null | |
| phone | string| null | |
| representative | string| null | |
| businessNumber | string| null | |
| scaleType | string| null | |
| approvalStatus | enum | 계량소 승인 상태draft · pending · approved · rejected · revoked |
| twoJointStatus | enum | none · requested · approved · rejected |
| scaleCapacityKg | integer| null | |
| inspectionValidUntil | string <date>| null | |
| bankName | string| null | |
| accountNumber | string| null | |
| indicatorConfigs | StationIndicatorConfig[] | |
| id | string <uuid> | |
| stationId | string <uuid> | |
| status | enum | not_configured · ready · error |
| port | string| null | |
| baudRate | integer| null | |
| lastTestedAt | string <date-time>| null | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| feeRules | StationFeeRule[] | |
| id | string <uuid> | |
| stationId | string <uuid> | |
| vehicleType | enum | 차량 톤수 구분ton5 · ton8 · ton10 · ton15 · ton25 |
| tier | string| null | 고객 등급(없으면 전체 적용) |
| amountKrw | integer | 계량 요금(원) |
| isActive | boolean | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"ownerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"region": "string",
"address": "string",
"detailAddress": "string",
"lat": 0,
"lng": 0,
"phone": "string",
"representative": "string",
"businessNumber": "string",
"scaleType": "string",
"approvalStatus": "draft",
"twoJointStatus": "none",
"scaleCapacityKg": 0,
"inspectionValidUntil": "2026-07-11",
"bankName": "string",
"accountNumber": "string",
"indicatorConfigs": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "not_configured",
"port": "string",
"baudRate": 0,
"lastTestedAt": "2026-07-11T09:00:00.000Z",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"feeRules": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"vehicleType": "ton5",
"tier": "string",
"amountKrw": 0,
"isActive": false,
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | read:station 스코프 없음 |
| 404 | STATION_001 | 계량소를 찾을 수 없음 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/weighing-records계량 기록 목록
키에 바인딩된 계량소의 계량 기록을 최신순으로 페이지네이션하여 반환한다. 각 항목에는 고객·차량·계량값(measurements)과 매칭된 결제(payment)가 포함된다.
쿼리 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| page | integer | 선택 | 페이지 번호(1 이상, 기본 1) |
| limit | integer | 선택 | 페이지 크기(1~100, 기본 20) |
| status | string | 선택 | 계량 기록 상태 필터in_progress · completed · cancelled |
| vehiclePlate | string | 선택 | 차량 번호 부분 검색(ILIKE) |
| cargo | string | 선택 | 품목명 부분 검색(ILIKE) |
| from | string <date-time> | 선택 | 생성 시각 하한(ISO8601) |
| to | string <date-time> | 선택 | 생성 시각 상한(ISO8601) |
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/weighing-records' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| items | WeighingRecord[] | |
| id | string <uuid> | |
| userId | string <uuid>| null | |
| createdByTerminalId | string <uuid>| null | |
| customerId | string <uuid>| null | |
| customer | object| null | 고객(거래처) |
| id | string <uuid> | |
| stationId | string <uuid> | |
| profileId | string <uuid>| null | |
| name | string | |
| representative | string| null | |
| phone | string| null | |
| address | string| null | |
| businessNumber | string| null | |
| memo | string| null | |
| tier | string | 고객 등급 |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehicleId | string <uuid>| null | |
| vehicle | object| null | 차량 |
| id | string <uuid> | |
| customerId | string <uuid>| null | |
| profileId | string <uuid>| null | |
| plateNumber | string | |
| vehicleType | enum | 차량 톤수 구분ton5 · ton8 · ton10 · ton15 · ton25 |
| isPrimary | boolean | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehiclePlate | string| null | |
| vehicleType | string| null | |
| firstStationId | string <uuid> | |
| secondStationId | string <uuid>| null | |
| cargoName | string| null | |
| partnerName | string| null | |
| note | string| null | |
| status | enum | 계량 기록 상태in_progress · completed · cancelled |
| twoJoint | boolean | |
| grossKg | number| null | 총중량(kg) |
| tareKg | number| null | 공차 중량(kg) |
| netKg | number| null | 실중량(kg) = gross - tare |
| amountKrw | integer| null | |
| firstWeighedAt | string <date-time>| null | |
| secondWeighedAt | string <date-time>| null | |
| cancelReason | string| null | |
| measurements | WeighingMeasurement[] | |
| id | string <uuid> | |
| recordId | string <uuid> | |
| stationId | string <uuid> | |
| terminalId | string <uuid>| null | |
| kind | enum | 계량 종류(gross=총중량, tare=공차)gross · tare |
| weightKg | number | 계량값(kg) |
| stabilityStatus | enum | 계량 안정 상태stable · unstable · overload |
| source | enum | 계량값 취득 경로hardware · mock · manual |
| measuredAt | string <date-time> | |
| latitude | number| null | |
| longitude | number| null | |
| createdAt | string <date-time> | |
| certificates | Certificate[] | 상세 조회에서만 포함 |
| id | string <uuid> | |
| recordId | string <uuid> | |
| type | enum | 증명서 종류standard · two_joint |
| status | enum | 증명서 상태pending · generated · sent · failed |
| objectKey | string| null | |
| url | string| null | 발급된 증명서 파일 URL |
| generatedAt | string <date-time>| null | |
| deliveries | CertificateDelivery[] | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| payment | object| null | 목록 조회에서만 매핑됨 |
| id | string <uuid> | |
| recordId | string <uuid>| null | |
| userId | string <uuid>| null | |
| stationId | string <uuid> | |
| amountKrw | integer | |
| status | enum | 결제 상태(outstanding=미수금)pending · paid · outstanding · cancelled |
| provider | string| null | |
| orderId | string | |
| paymentKey | string| null | PG 결제 키(민감정보 취급) |
| method | string| null | |
| paidAt | string <date-time>| null | |
| cancelledAt | string <date-time>| null | |
| cancelReason | string| null | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| page | integer | |
| limit | integer | |
| total | integer | |
| totalPages | integer |
응답 예시
{
"success": true,
"data": {
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"createdByTerminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customer": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"representative": "string",
"phone": "string",
"address": "string",
"businessNumber": "string",
"memo": "string",
"tier": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehicleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"vehicle": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"plateNumber": "string",
"vehicleType": "ton5",
"isPrimary": false,
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehiclePlate": "string",
"vehicleType": "string",
"firstStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"secondStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cargoName": "string",
"partnerName": "string",
"note": "string",
"status": "in_progress",
"twoJoint": false,
"grossKg": 0,
"tareKg": 0,
"netKg": 0,
"amountKrw": 0,
"firstWeighedAt": "2026-07-11T09:00:00.000Z",
"secondWeighedAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"measurements": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"terminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"kind": "gross",
"weightKg": 0,
"stabilityStatus": "stable",
"source": "hardware",
"measuredAt": "2026-07-11T09:00:00.000Z",
"latitude": 0,
"longitude": 0,
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"certificates": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "standard",
"status": "pending",
"objectKey": "string",
"url": "string",
"generatedAt": "2026-07-11T09:00:00.000Z",
"deliveries": [
{
"id": null,
"certificateId": null,
"channel": null,
"recipient": null,
"status": null,
"sentAt": null,
"failureReason": null,
"createdAt": null
}
],
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"payment": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amountKrw": 0,
"status": "pending",
"provider": "string",
"orderId": "string",
"paymentKey": "string",
"method": "string",
"paidAt": "2026-07-11T09:00:00.000Z",
"cancelledAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"page": 0,
"limit": 0,
"total": 0,
"totalPages": 0
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 쿼리 파라미터 검증 실패(page/limit/status 등) |
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | read:weighing 스코프 없음 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/weighing-records계량 기록 생성
키에 바인딩된 계량소에 신규 계량 기록을 생성한다. 계량소(firstStationId)는 키에서 강제되므로 본문으로 받지 않는다. 모든 필드는 선택이며, 생성된 기록은 상세 형태로 반환된다(status=in_progress).
요청 본문
| 필드 | 타입 | 설명 |
|---|---|---|
| customerId | string | 고객 ID |
| vehicleId | string | 차량 ID |
| vehiclePlate | string | 차량 번호 |
| vehicleType | string | 차량 구분 |
| cargoName | string | 품목명 |
| partnerName | string | 거래처명 |
| note | string | 메모 |
| amountKrw | integer | 금액(원) |
요청 예시
curl -X POST 'https://api.weighter.shop/agent/v1/weighing-records' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{
"customerId": "string",
"vehicleId": "string",
"vehiclePlate": "string",
"vehicleType": "string",
"cargoName": "string",
"partnerName": "string",
"note": "string",
"amountKrw": 0
}'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| userId | string <uuid>| null | |
| createdByTerminalId | string <uuid>| null | |
| customerId | string <uuid>| null | |
| customer | object| null | 고객(거래처) |
| id | string <uuid> | |
| stationId | string <uuid> | |
| profileId | string <uuid>| null | |
| name | string | |
| representative | string| null | |
| phone | string| null | |
| address | string| null | |
| businessNumber | string| null | |
| memo | string| null | |
| tier | string | 고객 등급 |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehicleId | string <uuid>| null | |
| vehicle | object| null | 차량 |
| id | string <uuid> | |
| customerId | string <uuid>| null | |
| profileId | string <uuid>| null | |
| plateNumber | string | |
| vehicleType | enum | 차량 톤수 구분ton5 · ton8 · ton10 · ton15 · ton25 |
| isPrimary | boolean | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehiclePlate | string| null | |
| vehicleType | string| null | |
| firstStationId | string <uuid> | |
| secondStationId | string <uuid>| null | |
| cargoName | string| null | |
| partnerName | string| null | |
| note | string| null | |
| status | enum | 계량 기록 상태in_progress · completed · cancelled |
| twoJoint | boolean | |
| grossKg | number| null | 총중량(kg) |
| tareKg | number| null | 공차 중량(kg) |
| netKg | number| null | 실중량(kg) = gross - tare |
| amountKrw | integer| null | |
| firstWeighedAt | string <date-time>| null | |
| secondWeighedAt | string <date-time>| null | |
| cancelReason | string| null | |
| measurements | WeighingMeasurement[] | |
| id | string <uuid> | |
| recordId | string <uuid> | |
| stationId | string <uuid> | |
| terminalId | string <uuid>| null | |
| kind | enum | 계량 종류(gross=총중량, tare=공차)gross · tare |
| weightKg | number | 계량값(kg) |
| stabilityStatus | enum | 계량 안정 상태stable · unstable · overload |
| source | enum | 계량값 취득 경로hardware · mock · manual |
| measuredAt | string <date-time> | |
| latitude | number| null | |
| longitude | number| null | |
| createdAt | string <date-time> | |
| certificates | Certificate[] | 상세 조회에서만 포함 |
| id | string <uuid> | |
| recordId | string <uuid> | |
| type | enum | 증명서 종류standard · two_joint |
| status | enum | 증명서 상태pending · generated · sent · failed |
| objectKey | string| null | |
| url | string| null | 발급된 증명서 파일 URL |
| generatedAt | string <date-time>| null | |
| deliveries | CertificateDelivery[] | |
| id | string <uuid> | |
| certificateId | string <uuid> | |
| channel | enum | 증명서 발송 채널email · sms · kakao |
| recipient | string | |
| status | enum | 증명서 발송 상태pending · sent · failed |
| sentAt | string <date-time>| null | |
| failureReason | string| null | |
| createdAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| payment | object| null | 목록 조회에서만 매핑됨 |
| id | string <uuid> | |
| recordId | string <uuid>| null | |
| userId | string <uuid>| null | |
| stationId | string <uuid> | |
| amountKrw | integer | |
| status | enum | 결제 상태(outstanding=미수금)pending · paid · outstanding · cancelled |
| provider | string| null | |
| orderId | string | |
| paymentKey | string| null | PG 결제 키(민감정보 취급) |
| method | string| null | |
| paidAt | string <date-time>| null | |
| cancelledAt | string <date-time>| null | |
| cancelReason | string| null | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"createdByTerminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customer": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"representative": "string",
"phone": "string",
"address": "string",
"businessNumber": "string",
"memo": "string",
"tier": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehicleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"vehicle": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"plateNumber": "string",
"vehicleType": "ton5",
"isPrimary": false,
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehiclePlate": "string",
"vehicleType": "string",
"firstStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"secondStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cargoName": "string",
"partnerName": "string",
"note": "string",
"status": "in_progress",
"twoJoint": false,
"grossKg": 0,
"tareKg": 0,
"netKg": 0,
"amountKrw": 0,
"firstWeighedAt": "2026-07-11T09:00:00.000Z",
"secondWeighedAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"measurements": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"terminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"kind": "gross",
"weightKg": 0,
"stabilityStatus": "stable",
"source": "hardware",
"measuredAt": "2026-07-11T09:00:00.000Z",
"latitude": 0,
"longitude": 0,
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"certificates": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "standard",
"status": "pending",
"objectKey": "string",
"url": "string",
"generatedAt": "2026-07-11T09:00:00.000Z",
"deliveries": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"certificateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "email",
"recipient": "string",
"status": "pending",
"sentAt": "2026-07-11T09:00:00.000Z",
"failureReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"payment": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amountKrw": 0,
"status": "pending",
"provider": "string",
"orderId": "string",
"paymentKey": "string",
"method": "string",
"paidAt": "2026-07-11T09:00:00.000Z",
"cancelledAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 본문 검증 실패(amountKrw 음수 등) |
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | write:weighing 스코프 없음 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/weighing-records/{id}계량 기록 상세
단일 계량 기록을 고객·차량·계량값(measurements)·증명서(certificates)와 함께 반환한다. 다른 계량소의 기록은 존재를 숨기기 위해 404로 응답한다.
경로 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | string <uuid> | 필수 | 계량 기록 UUID |
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/weighing-records/a1b2c3d4-e5f6-7890-abcd-ef1234567890' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| userId | string <uuid>| null | |
| createdByTerminalId | string <uuid>| null | |
| customerId | string <uuid>| null | |
| customer | object| null | 고객(거래처) |
| id | string <uuid> | |
| stationId | string <uuid> | |
| profileId | string <uuid>| null | |
| name | string | |
| representative | string| null | |
| phone | string| null | |
| address | string| null | |
| businessNumber | string| null | |
| memo | string| null | |
| tier | string | 고객 등급 |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehicleId | string <uuid>| null | |
| vehicle | object| null | 차량 |
| id | string <uuid> | |
| customerId | string <uuid>| null | |
| profileId | string <uuid>| null | |
| plateNumber | string | |
| vehicleType | enum | 차량 톤수 구분ton5 · ton8 · ton10 · ton15 · ton25 |
| isPrimary | boolean | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| vehiclePlate | string| null | |
| vehicleType | string| null | |
| firstStationId | string <uuid> | |
| secondStationId | string <uuid>| null | |
| cargoName | string| null | |
| partnerName | string| null | |
| note | string| null | |
| status | enum | 계량 기록 상태in_progress · completed · cancelled |
| twoJoint | boolean | |
| grossKg | number| null | 총중량(kg) |
| tareKg | number| null | 공차 중량(kg) |
| netKg | number| null | 실중량(kg) = gross - tare |
| amountKrw | integer| null | |
| firstWeighedAt | string <date-time>| null | |
| secondWeighedAt | string <date-time>| null | |
| cancelReason | string| null | |
| measurements | WeighingMeasurement[] | |
| id | string <uuid> | |
| recordId | string <uuid> | |
| stationId | string <uuid> | |
| terminalId | string <uuid>| null | |
| kind | enum | 계량 종류(gross=총중량, tare=공차)gross · tare |
| weightKg | number | 계량값(kg) |
| stabilityStatus | enum | 계량 안정 상태stable · unstable · overload |
| source | enum | 계량값 취득 경로hardware · mock · manual |
| measuredAt | string <date-time> | |
| latitude | number| null | |
| longitude | number| null | |
| createdAt | string <date-time> | |
| certificates | Certificate[] | 상세 조회에서만 포함 |
| id | string <uuid> | |
| recordId | string <uuid> | |
| type | enum | 증명서 종류standard · two_joint |
| status | enum | 증명서 상태pending · generated · sent · failed |
| objectKey | string| null | |
| url | string| null | 발급된 증명서 파일 URL |
| generatedAt | string <date-time>| null | |
| deliveries | CertificateDelivery[] | |
| id | string <uuid> | |
| certificateId | string <uuid> | |
| channel | enum | 증명서 발송 채널email · sms · kakao |
| recipient | string | |
| status | enum | 증명서 발송 상태pending · sent · failed |
| sentAt | string <date-time>| null | |
| failureReason | string| null | |
| createdAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| payment | object| null | 목록 조회에서만 매핑됨 |
| id | string <uuid> | |
| recordId | string <uuid>| null | |
| userId | string <uuid>| null | |
| stationId | string <uuid> | |
| amountKrw | integer | |
| status | enum | 결제 상태(outstanding=미수금)pending · paid · outstanding · cancelled |
| provider | string| null | |
| orderId | string | |
| paymentKey | string| null | PG 결제 키(민감정보 취급) |
| method | string| null | |
| paidAt | string <date-time>| null | |
| cancelledAt | string <date-time>| null | |
| cancelReason | string| null | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"createdByTerminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customer": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"representative": "string",
"phone": "string",
"address": "string",
"businessNumber": "string",
"memo": "string",
"tier": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehicleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"vehicle": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"profileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"plateNumber": "string",
"vehicleType": "ton5",
"isPrimary": false,
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"vehiclePlate": "string",
"vehicleType": "string",
"firstStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"secondStationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cargoName": "string",
"partnerName": "string",
"note": "string",
"status": "in_progress",
"twoJoint": false,
"grossKg": 0,
"tareKg": 0,
"netKg": 0,
"amountKrw": 0,
"firstWeighedAt": "2026-07-11T09:00:00.000Z",
"secondWeighedAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"measurements": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"terminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"kind": "gross",
"weightKg": 0,
"stabilityStatus": "stable",
"source": "hardware",
"measuredAt": "2026-07-11T09:00:00.000Z",
"latitude": 0,
"longitude": 0,
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"certificates": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "standard",
"status": "pending",
"objectKey": "string",
"url": "string",
"generatedAt": "2026-07-11T09:00:00.000Z",
"deliveries": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"certificateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "email",
"recipient": "string",
"status": "pending",
"sentAt": "2026-07-11T09:00:00.000Z",
"failureReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"payment": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amountKrw": 0,
"status": "pending",
"provider": "string",
"orderId": "string",
"paymentKey": "string",
"method": "string",
"paidAt": "2026-07-11T09:00:00.000Z",
"cancelledAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
},
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | read:weighing 스코프 없음 |
| 404 | WEIGHING_001 | 기록이 없거나 다른 계량소 소속(존재 비노출) |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/certificates증명서 목록
키에 바인딩된 계량소의 계량 기록에 속한 증명서를 최신순으로 페이지네이션하여 반환한다. 각 항목에는 계량 기록(record)과 발송 이력(deliveries)이 포함된다.
쿼리 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| page | integer | 선택 | 페이지 번호(1 이상, 기본 1) |
| limit | integer | 선택 | 페이지 크기(1~100, 기본 20) |
| recordId | string <uuid> | 선택 | 특정 계량 기록의 증명서만 조회 |
| status | string | 선택 | 증명서 상태 필터pending · generated · sent · failed |
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/certificates' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| items | Certificate[] | |
| id | string <uuid> | |
| recordId | string <uuid> | |
| type | enum | 증명서 종류standard · two_joint |
| status | enum | 증명서 상태pending · generated · sent · failed |
| objectKey | string| null | |
| url | string| null | 발급된 증명서 파일 URL |
| generatedAt | string <date-time>| null | |
| deliveries | CertificateDelivery[] | |
| id | string <uuid> | |
| certificateId | string <uuid> | |
| channel | enum | 증명서 발송 채널email · sms · kakao |
| recipient | string | |
| status | enum | 증명서 발송 상태pending · sent · failed |
| sentAt | string <date-time>| null | |
| failureReason | string| null | |
| createdAt | string <date-time> | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| page | integer | |
| limit | integer | |
| total | integer | |
| totalPages | integer |
응답 예시
{
"success": true,
"data": {
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "standard",
"status": "pending",
"objectKey": "string",
"url": "string",
"generatedAt": "2026-07-11T09:00:00.000Z",
"deliveries": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"certificateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "email",
"recipient": "string",
"status": "pending",
"sentAt": "2026-07-11T09:00:00.000Z",
"failureReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z"
}
],
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"page": 0,
"limit": 0,
"total": 0,
"totalPages": 0
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 쿼리 파라미터 검증 실패 |
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | read:certificates 스코프 없음 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/certificates/{id}/deliveries증명서 발송 요청
지정한 증명서를 채널(email/sms/kakao)로 발송 요청한다. channel=email이고 recipient가 있으면 즉시 이메일을 발송하며, 증명서 상태는 sent로 갱신된다. 다른 계량소의 증명서는 404로 응답한다.
경로 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | string <uuid> | 필수 | 증명서 UUID |
요청 본문*
| 필드 | 타입 | 설명 |
|---|---|---|
| channel* | enum | 증명서 발송 채널email · sms · kakao |
| recipient* | string | 수신자(email/전화번호/카카오 식별자) |
요청 예시
curl -X POST 'https://api.weighter.shop/agent/v1/certificates/a1b2c3d4-e5f6-7890-abcd-ef1234567890/deliveries' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{
"channel": "email",
"recipient": "string"
}'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| certificateId | string <uuid> | |
| channel | enum | 증명서 발송 채널email · sms · kakao |
| recipient | string | |
| status | enum | 증명서 발송 상태pending · sent · failed |
| sentAt | string <date-time>| null | |
| failureReason | string| null | |
| createdAt | string <date-time> |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"certificateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "email",
"recipient": "string",
"status": "pending",
"sentAt": "2026-07-11T09:00:00.000Z",
"failureReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z"
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 본문 검증 실패(channel/recipient 누락 등) |
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | write:certificates 스코프 없음 |
| 404 | CERTIFICATE_001 | 증명서가 없거나 다른 계량소 소속(존재 비노출) |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/payments결제·미수금 목록
키에 바인딩된 계량소의 결제 내역을 최신순으로 페이지네이션하여 반환한다. status=outstanding로 미수금만 필터할 수 있다.
쿼리 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| page | integer | 선택 | 페이지 번호(1 이상, 기본 1) |
| limit | integer | 선택 | 페이지 크기(1~100, 기본 20) |
| status | string | 선택 | 결제 상태 필터pending · paid · outstanding · cancelled |
| from | string <date-time> | 선택 | 생성 시각 하한(ISO8601) |
| to | string <date-time> | 선택 | 생성 시각 상한(ISO8601) |
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/payments' \
-H 'Authorization: Bearer wtr_ak_xxxxxxxxxxxxxxxxxxxxxxxx'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| items | Payment[] | |
| id | string <uuid> | |
| recordId | string <uuid>| null | |
| userId | string <uuid>| null | |
| stationId | string <uuid> | |
| amountKrw | integer | |
| status | enum | 결제 상태(outstanding=미수금)pending · paid · outstanding · cancelled |
| provider | string| null | |
| orderId | string | |
| paymentKey | string| null | PG 결제 키(민감정보 취급) |
| method | string| null | |
| paidAt | string <date-time>| null | |
| cancelledAt | string <date-time>| null | |
| cancelReason | string| null | |
| createdAt | string <date-time> | |
| updatedAt | string <date-time> | |
| page | integer | |
| limit | integer | |
| total | integer | |
| totalPages | integer |
응답 예시
{
"success": true,
"data": {
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recordId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amountKrw": 0,
"status": "pending",
"provider": "string",
"orderId": "string",
"paymentKey": "string",
"method": "string",
"paidAt": "2026-07-11T09:00:00.000Z",
"cancelledAt": "2026-07-11T09:00:00.000Z",
"cancelReason": "string",
"createdAt": "2026-07-11T09:00:00.000Z",
"updatedAt": "2026-07-11T09:00:00.000Z"
}
],
"page": 0,
"limit": 0,
"total": 0,
"totalPages": 0
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 쿼리 파라미터 검증 실패 |
| 401 | AGENT_001 | 키 형식 오류 또는 존재하지 않는 키 |
| 401 | AGENT_002 | 회수·만료된 키 |
| 403 | AGENT_003 | read:payments 스코프 없음 |
| 429 | AGENT_004 | 분당 요청 한도(60) 초과 |
/agent/v1/openapi.jsonOpenAPI 문서(공개)
Agent API v1의 OpenAPI 3.0 문서를 인증 없이 반환한다. 응답은 표준 에러 봉투로 감싸지 않고 OpenAPI 문서 원본을 그대로 반환한다.
요청 예시
curl -X GET 'https://api.weighter.shop/agent/v1/openapi.json'응답 필드
필드 정보 없음
응답 예시
{
"openapi": "3.0.3",
"info": {
"title": "Weighter Agent API"
},
"paths": {
"...": {}
}
}agent-keys
에이전트 API 키 관리 — 계량소 소장(OWNER) 로그인(JWT)으로 키를 발급·조회·회수한다. 평문 키는 생성 시 1회만 반환된다.
/agent-keys에이전트 키 목록
로그인한 소장이 소유한 에이전트 키 목록을 반환한다. `stationId`를 주면 해당 계량소 키만, 없으면 소유한 전체 키를 반환한다. 응답에는 평문 키나 해시가 포함되지 않는다.
쿼리 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| stationId | string <uuid> | 선택 | 계량소 UUID(생략 시 전체) |
요청 예시
curl -X GET 'https://api.weighter.shop/agent-keys' \
-H 'Authorization: Bearer <ACCESS_TOKEN>'응답 필드 (data)
배열 응답
응답 예시
{
"success": true,
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"keyPrefix": "string",
"scopes": [
"read:station"
],
"expiresAt": "2026-07-11T09:00:00.000Z",
"lastUsedAt": "2026-07-11T09:00:00.000Z",
"revokedAt": "2026-07-11T09:00:00.000Z",
"createdAt": "2026-07-11T09:00:00.000Z"
}
]
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 401 | AUTH_001 | 로그인 필요(액세스 토큰 없음/무효) |
| 403 | AUTH_004 | OWNER 권한 아님 |
/agent-keys에이전트 키 발급
계량소 소장(OWNER)이 지정 계량소에 대한 에이전트 키를 발급한다. 응답의 `plainKey`(평문 `wtr_ak_...`)는 이때 단 한 번만 노출되며, 서버에는 SHA-256 해시만 저장된다. 이후에는 복구할 수 없다.
요청 본문*
| 필드 | 타입 | 설명 |
|---|---|---|
| stationId* | string <uuid> | 키를 바인딩할 계량소 UUID |
| name* | string | 키 식별용 이름 |
| scopes* | AgentScope[] | 부여할 스코프(최소 1개, 중복 불가) |
| expiresAt | string <date-time> | 만료 시각(ISO8601, 생략 시 무기한) |
요청 예시
curl -X POST 'https://api.weighter.shop/agent-keys' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"stationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"scopes": [
"read:station"
],
"expiresAt": "2026-07-11T09:00:00.000Z"
}'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| name | string | |
| keyPrefix | string | 표시용 접두부(wtr_ak_ + 앞 5자) |
| scopes | AgentScope[] | |
| expiresAt | string <date-time>| null | |
| createdAt | string <date-time> | |
| plainKey | string | 평문 키(wtr_ak_...). 이 응답에서만 노출되며 이후 복구 불가. |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "string",
"keyPrefix": "string",
"scopes": [
"read:station"
],
"expiresAt": "2026-07-11T09:00:00.000Z",
"createdAt": "2026-07-11T09:00:00.000Z",
"plainKey": "wtr_ak_9f2c1a7b3e5d..."
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 400 | COMMON_001 | 본문 검증 실패(name/scopes/stationId 등) |
| 401 | AUTH_001 | 로그인 필요(액세스 토큰 없음/무효) |
| 403 | AUTH_004 | OWNER 권한 아님 또는 본인 소유 계량소 아님 |
/agent-keys/{id}에이전트 키 회수
키를 즉시 회수(revoke)한다. 회수된 키로 Agent API를 호출하면 401(AGENT_002)로 거부된다. 회수 시각(revokedAt)이 반환된다.
경로 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | string <uuid> | 필수 | 에이전트 키 UUID |
요청 예시
curl -X DELETE 'https://api.weighter.shop/agent-keys/a1b2c3d4-e5f6-7890-abcd-ef1234567890' \
-H 'Authorization: Bearer <ACCESS_TOKEN>'응답 필드 (data)
| 필드 | 타입 | 설명 |
|---|---|---|
| id | string <uuid> | |
| revokedAt | string <date-time> |
응답 예시
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"revokedAt": "2026-07-11T09:00:00.000Z"
}
}에러 케이스
| HTTP | 코드 | 발생 조건 |
|---|---|---|
| 401 | AUTH_001 | 로그인 필요(액세스 토큰 없음/무효) |
| 403 | AUTH_004 | OWNER 권한 아님 또는 본인 소유 키 아님 |
| 404 | COMMON_002 | 키를 찾을 수 없음 |