오토메타 연동 API 문서

오토메타 ↔ 비스캣 10종 API의 엔드포인트·페이로드·인증·재시도 규약입니다. 10종 모두 비스캣이 작성·제공합니다. 동작 흐름은 개발 시나리오를 함께 참조하세요.

1. 공통 규약

API 키 취급 주의

2. 10종 API 목록

#API방향Method / Path인증
0접속·인증 확인 (연동 초기 점검)오토메타 → 비스캣GET /v1/automata/pingAPI Key
1배송 가능 여부 (주문 이후)오토메타 → 비스캣POST /v1/automata/delivery/availabilityAPI Key
2로봇 배차 요청오토메타 → 비스캣POST /v1/automata/dispatchAPI Key + Idempotency
3로봇 배차 취소오토메타 → 비스캣POST /v1/automata/dispatch/{orderId}/cancelAPI Key
4-A위치기반 실시간 배송정보 (단발 조회)오토메타 → 비스캣GET /v1/automata/dispatch/{orderId}/trackingAPI Key
4-B위치기반 실시간 배송정보 (SSE 스트리밍)오토메타 → 비스캣GET /v1/automata/dispatch/{orderId}/tracking/streamAPI Key
5고객 도착 예상시간 조회오토메타 → 비스캣GET /v1/automata/dispatch/{orderId}/etaAPI Key
6매장(점포) 도착비스캣 → 오토메타POST {콜백URL} (robot.shop_arrived)HMAC 서명
7배달 출발 알림비스캣 → 오토메타POST {콜백URL} (delivery.departed)HMAC 서명
8배달 예정/도착/하차 완료비스캣 → 오토메타POST {콜백URL} (delivery.status_changed)HMAC 서명
9알림 노티 (신규)비스캣 → 오토메타POST {콜백URL} (notify.event)HMAC 서명
10박스 개폐 (하차) — 앱(WEB) 원격오토메타 → 비스캣POST /v1/automata/dispatch/{orderId}/unlockAPI Key

URL 경로의 {orderId}는 오토메타가 발급한 전역 유니크 요청ID로, 후속 호출(#3·#4·#5·#10)·콜백(#6~#9)의 주키로 사용됩니다. 오토메타는 별도 robotId를 보관할 필요가 없습니다 — 배차 응답으로 내려가는 robotId는 표시·로그용 정보성 필드입니다.

#0 접속·인증 확인 — GET /v1/automata/ping

연동 초기·배포 후 자격증명(X-Api-Key-Id + X-Api-Key)과 연결을 자가 점검하는 부작용 없는 엔드포인트입니다(주문·미션을 만들지 않음). 200 응답이면 인증·연결 정상이며 { "result":"SUCCESS", "data":{ "keyId", "authenticated":true, "serverTime", "message" } }를 반환합니다. 401이면 헤더 누락 또는 키 불일치(발급 정보 재확인), 그 외 4xx/5xx·타임아웃이면 네트워크·엔드포인트 설정을 확인하세요. 운영에 영향이 없으므로 헬스체크·모니터링 프로브로도 사용할 수 있습니다.

3. 인바운드 (오토메타 → 비스캣)

POST /v1/automata/delivery/availability — #1 배송 가능 여부

shopId(매장, 필수)·dong·ho(세대, 필수)·boxCount(필요 박스 수, 필수)를 견적에 전달하면, 로봇이 점포·세대까지의 도착 예상시간을 합산한 etaMinutes를 산출하고 박스 수용 가능 여부까지 반영해 available을 판정합니다. deliveryTypetrash_pickup(쓰레기 픽업)이어도 세대가 픽업 지점이므로 dong·ho는 동일하게 필수입니다. 견적도 배차(#2)와 동일하게 매장(shopId)·세대(dong·ho) 목적지 노드가 모두 매핑돼야 하며, 없으면 로봇 견적(offer) 전 422 DESTINATION_NOT_MATCHED로 거부됩니다.

요청
{
  "deliveryType": "delivery|trash_pickup", // 구분 (매장/쓰레기)
  "siteId": "APT-1023",                     // 단지코드
  "shopId": "string",                       // 매장(점포) ID (필수)
  "dong": "101",                            // 세대 동 (필수)
  "ho": "1502",                             // 세대 호 (필수)
  "boxCount": 2                             // 필요한 박스 수 (1~4, 필수)
}
200 응답
{
  "result": "SUCCESS",
  "data": {
    "available": true,
    "etaMinutes": 11           // 점포+세대 도착 예상시간 합(분)
  }
}
에러422 AUTOMA_INVALID_PAYLOAD (dong·ho 누락, boxCount 누락/범위(1~4) 위반 시), 422 DESTINATION_NOT_MATCHED (주소 매핑에 매장(shopId)·세대(dong·ho) 노드 없음 — shopId 누락 포함, 로봇 견적(offer) 전 거부)

available=false이거나 견적 요청이 타임아웃되면 etaMinutesnull입니다.

POST /v1/automata/dispatch — #2 로봇 배차 요청

주문 필드: orderId · deliveryType · shopId · siteId · dong · ho · boxCount · ownerPin. dong·ho(세대)·boxCount는 #1과 동일한 세대·박스 입력 정책으로 필수이며, 누락 시 422 AUTOMA_INVALID_PAYLOAD로 거부됩니다. 비대면/대면 방식은 배차 로봇의 설정(auto_drop_off)에 따라 비스캣이 결정하며, 그 결과를 응답 autoDropoff로 알려줍니다. 비스캣은 대면 배송 시(autoDropoff: false) 항상 userPin(4자리)을 발행해 응답에 동봉합니다.

요청
{
  "shopId": "string",
  "shopName": "string",
  "orderId": "string",            // 요청ID (외부 식별자)
  "deliveryType": "delivery|trash_pickup",
  "siteId": "APT-1023",           // 단지코드
  "dong": "101",                  // 세대 동 (필수)
  "ho": "1502",                   // 세대 호 (필수)
  "boxCount": 2,                  // 필요한 박스 수 (1~4, 필수) — 주문 수량 기준
  "ownerPin": "4821"              // 점주용 PIN — 고정 4자리, 오토메타가 동봉
}
200 응답
{
  "result": "SUCCESS",
  "data": {
    "missionId": "uuid",
    "robotId": "uuid",            // 배차로봇ID — 정보성(표시·로그용). 후속 호출 주키는 orderId
    "etaMinutes": 7,              // 도착 예상시간(분) — 점포+세대 도착 예상시간 합(#1 견적과 동일 집계)
    "autoDropoff": false,         // 배차 로봇의 비대면 하차 가능 여부 — true=비대면(자동 하차), false=대면(userPin 필요)
    "userPin": "7390",            // 사용자 PIN — 비스캣 생성 랜덤 4자리 (대면 배송 시 항상 발행)
    "boxSlots": [1, 3],           // 적재할 박스 번호 배열 (관제 할당, 1~4)
    "status": "CREATED",
    "expiresAt": "2026-06-04T14:30:00+09:00"
  }
}
에러409 ORDER_DUPLICATE, 422 AUTOMA_INVALID_PAYLOAD (dong·ho 누락 — #1과 동일하게 세대 필수), 422 DESTINATION_NOT_MATCHED (주소 매핑에 매장(shopId)·세대(dong·ho) 노드 없음), 503 NO_ROBOT_AVAILABLE, 422 DISPATCH_LOAD_EXCEEDED (boxCount 누락·범위(1~4) 위반·적재함 4칸 초과)

POST /v1/automata/dispatch/{orderId}/cancel — #3 배차 취소

요청
{ "shopId": "string" }                  // orderId는 URL 경로
200 응답
{ "result": "SUCCESS", "data": { "missionId": "uuid", "status": "ABORTED" } }
에러404 DISPATCH_NOT_FOUND (orderId 미존재), 409 DISPATCH_NOT_CANCELABLE (출발 후 취소 불가)

GET /v1/automata/dispatch/{orderId}/tracking — #4-A 위치기반 실시간 배송정보 (단발 조회)

화면 재진입·통신 실패 복구처럼 드물게 1회 가져갈 때. 지속 갱신은 #4-B SSE 권장 (양자택일).

200 응답
{
  "result": "SUCCESS",
  "data": {
    "robotId": "uuid",
    "position": { "x": 0, "y": 0, "th": 0 },
    "phase": "to_shop|at_shop|to_household|at_household|returning",
    "etaMinutes": 4
  }
}

GET /v1/automata/dispatch/{orderId}/tracking/stream — #4-B 위치기반 실시간 배송정보 (SSE 스트리밍)

지도 위 로봇 마커 등 지속 갱신용. 비스캣이 위치·상태 변경 시점에 push.

Content-Typetext/event-stream
인증X-Api-Key 헤더. 브라우저 표준 EventSource로 호출 시 쿼리스트링 fallback 협의 필요
이벤트 예시
event: position
id: 1716893405000
data: {"robotId":"uuid","position":{...},"phase":"to_shop","etaMinutes":4}

event: heartbeat
data: {}

event: position
id: 1716893490000
data: {"robotId":"uuid","position":{...},"phase":"at_household","etaMinutes":0}

event: complete
data: {"finalStatus":"completed"}
이벤트 종류position (변경 시점, 최대 1Hz) · heartbeat (15s keep-alive) · complete (terminal state 진입 시 close) · error (비정상 종료 — data에 결과 코드·메시지)
재연결표준 Last-Event-ID 헤더로 마지막 수신 ID 전송 → 서버는 그 이후 변경분 또는 현재 스냅샷부터 재개
유지 시간 한도connection 30분. 그보다 길면 클라이언트 재연결
주요 에러초기 연결: DISPATCH_NOT_FOUND (404), MISSION_COMPLETED (410) — body 없이 close. 스트림 중간 오류는 error 이벤트로 전달

GET /v1/automata/dispatch/{orderId}/eta — #5 고객 도착 예상시간

쿼리?shopId=...
200 응답
{ "result": "SUCCESS", "data": { "robotId": "uuid", "etaMinutes": 4 } }

POST /v1/automata/dispatch/{orderId}/unlock — #10 박스 개폐 (하차)

대면 배송(autoDropoff: false)에서 주문자가 오토메타 앱(WEB)에서 박스를 여는 원격 개폐입니다. 앱이 orderId로 unlock을 요청하면 비스캣이 해당 주문에 배차된 로봇의 박스를 엽니다. 로봇이 고객 위치에 도착(arrived)한 뒤에만 허용됩니다.

요청
{ "shopId": "string" }                  // orderId는 URL 경로
200 응답
{ "result": "SUCCESS", "data": { "missionId": "uuid", "boxSlots": [1, 3], "status": "OPENED" } }
에러404 DISPATCH_NOT_FOUND (orderId 미존재), 409 UNLOCK_NOT_READY (도착 전 — 개폐 불가)

4. 아웃바운드 콜백 (비스캣 → 오토메타)

#6~#9는 비스캣이 오토메타 콜백 URL로 발신합니다. 공통 형식·서명·재시도를 따르며, X-Zeroworks-Event로 종류를 구분합니다.

콜백 요청 형식

POST {콜백URL}
Headers:
  X-Zeroworks-Event: robot.shop_arrived | delivery.departed | delivery.status_changed | notify.event
  X-Zeroworks-Signature: HMAC-SHA256(secret, body)   // secret = 콘솔(서비스 설정)에서 발급받은 콜백 서명 키, 대상 = 요청 body 원문
  X-Zeroworks-Timestamp: Unix timestamp (초 단위, 예: 1783644212)
  X-Zeroworks-Delivery: uuid (재시도 시 동일 → 중복 수신 무시용 유니크 키)

서명 검증: secret은 콘솔(서비스 설정)에서 발급받은 콜백 서명 키입니다. 수신 시 HMAC-SHA256(secret, 수신 body 원문)을 계산해 X-Zeroworks-Signature와 일치하는지 확인하세요 (대상은 body 원문 그대로 — timestamp 등은 서명에 포함하지 않음. timestamp·delivery는 별도 헤더).

#6 매장 도착
robot.shop_arrived
{
  "shopId": "string",
  "orderId": "string", "robotId": "uuid",
  "boxSlots": [1, 3],            // 적재할 박스 번호 배열 (1~4)
  "pin": "4821"                  // 점주가 박스 개방에 입력할 핀번호
}
#7 배달 출발
delivery.departed
{
  "shopId": "string",
  "orderId": "string", "robotId": "uuid"
}                                // 박스 닫힘이 출발 트리거
#8 예정/도착/하차
delivery.status_changed
{
  "phase": "scheduled|arrived|unloaded",
  "shopId": "string",
  "orderId": "string", "robotId": "uuid",
  "etaMinutes": 4
}
#9 알림 노티
notify.event
{
  "code": "NOTI_ETA_5MIN",     // 상태 식별자 코드만 전달
  "orderId": "string", "robotId": "uuid",
  "occurredAt": "2026-06-04T14:30:00+09:00"
}                              // 표출 문구는 오토메타가 관리

재시도 정책

알림 코드 카탈로그

비스캣은 코드(상태 식별자)만 콜백으로 전달하고, 사용자 표출 문구·최종 표출 채널은 오토메타가 관리합니다. 아래는 콜백 발행 대상 코드입니다. 표출 채널·임계값(N·M분)·최종 코드명은 제안값이며 협의로 확정합니다.

코드발생 시점표출 채널(제안)상태
NOTI_DISPATCHED배차 확정(로봇 배정 완료)주문자
NOTI_PICKED_UP매장 상차 완료·배송 시작주문자
NOTI_ETA_5MIN하차지 도착 약 5분 전주문자 · 세대
NOTI_ARRIVED하차지(세대) 도착주문자 · 세대
NOTI_DELIVERED수령 완료주문자
NOTI_PICKUP_REMINDER도착 후 N분 미수령 — 재안내주문자 · 세대정책 협의 필요
NOTI_PICKUP_TIMEOUT미수령 M분 초과 — 회수 전환주문자 · 점주정책 협의 및 로봇 개발 필요
NOTI_RETURNING미수령 회수·복귀 시작주문자 · 점주정책 협의 및 로봇 개발 필요
NOTI_RETURNED회수 완료주문자 · 점주정책 협의 및 로봇 개발 필요
NOTI_USER_CANCEL사용자 주문 취소주문자
NOTI_MISSION_EXPIRED미션 만료주문자 · 점주정책 협의 및 로봇 개발 필요
NOTI_COLLISION충돌 감지 — 지연 안내주문자
NOTI_TRASH_ETA_5MIN수거 로봇 도착 약 5분 전세대
NOTI_TRASH_ARRIVED수거 지점(세대 앞) 도착세대
NOTI_TRASH_COLLECTED배출물 수거 완료세대
NOTI_TRASH_TIMEOUT미배출 N분 경과세대정책 협의 필요

5. 에러 코드 (주문·배차 관련 발췌)

코드HTTP의미
AUTOMA_INVALID_PAYLOAD422배송/배차 페이로드 검증 실패
ORDER_DUPLICATE409동일 Idempotency-Key로 다른 페이로드
DISPATCH_LOAD_EXCEEDED422요청 박스 수(boxCount)가 적재함 4칸 초과 — 배차 거부
DESTINATION_NOT_MATCHED422주소 매핑에 매장(shopId)·세대(dong·ho)에 해당하는 목적지 노드 없음 — 배송 가능 여부(#1)·배차(#2) 공통, 로봇 견적·배차(offer) 전 거부
NO_ROBOT_AVAILABLE503디스패치 가능 로봇 없음 (정책상 거절)
DISPATCH_NOT_FOUND404취소 대상 배차 없음
DISPATCH_NOT_CANCELABLE409출발 후 취소 불가
RATE_LIMIT_EXCEEDED429레이트 리밋 초과 — Retry-After 준수