메인 콘텐츠로 건너뛰기
이 API 는 Client SDK 키(osk_ 접두사) 로 인증합니다. 추천 실행은 비동기(202) + 폴링 구조입니다.

전체 흐름

1. POST   /v1/profile/{profile_id}/session/start        (Profile 세션 시작 → session_id 발급)
2. POST   /v1/chat/{profile_id}                         (LLM 세션 생성; body 없음)
3. POST   /v1/profile/{profile_id}/session/stamp        (status="CHAT" 스탬프)
4. POST   /v1/chat/{profile_id}/recommend               (추천 kickoff, 202)
5. GET    /v1/chat/{profile_id}/recommend/{session_id}  (0.5 s 간격 폴링)
6. DELETE /v1/chat/{profile_id}/session/{session_id}    (세션 종료)
클라이언트는 profile_id 와 세션 시작 응답으로 받은 session_id 만 기억하면 됩니다. 프로필에 저장된 name / gender / age / locale 은 서버가 자동으로 읽어 LLM 프롤로그를 만듭니다.

세션 상태

응답의 status 로 폴링을 제어합니다.
의미클라이언트 동작
CHAT파이프라인 실행 중0.5 s 후 재폴링
READY직전 추천 결과 첨부됨back_list_status == "completed"result 사용
ERROR파이프라인 실패last_error 확인
ENDED세션 종료됨 (DELETE or 1 h 비활동)404 반환, 새 세션 필요

1. 채팅 세션 생성

POST /v1/chat/{profile_id}
요청 body 는 필요하지 않습니다. 프로필에 이미 등록된 name / gender / age / locale 을 서버가 꺼내 LLM user_query 프롤로그를 자동 생성합니다. 선행 조건: POST /v1/profile/{profile_id}/session/startProfile 세션이 이미 시작되어 있어야 합니다. 없으면 SESSION_NOT_STARTED 409.

Response 200

{
  "success": true,
  "data": {
    "session_id": "a14b2f9c-3d5e-4f2a-9a8b-1c2d3e4f5a6b",
    "profile_id": "...",
    "query_results": {
      "session": { "session_id": "...", "status": "READY", "back_list_status": "not_started" }
    }
  }
}
session_id 는 Profile 세션 ID 와 동일한 값이며, 이후 모든 recommend/poll/delete 호출에 그대로 사용합니다.

2. 추천 kickoff

POST /v1/chat/{profile_id}/recommend
선행 조건: 세션의 최신 stamp 상태가 CHAT 이어야 합니다. 그 외 상태에서는 STAGE_NOT_CHAT 409 로 거부. stamp 전환은 POST /v1/profile/{profile_id}/session/stamp 로 수행.

Request

{
  "session_id": "a14b2f9c-3d5e-4f2a-9a8b-1c2d3e4f5a6b",
  "prompt": "오늘 저녁 카레 땡기는데"
}
필드타입필수설명
session_idstringO1번에서 받은 세션 ID
promptstringO사용자 질의. 서버 내부에서 llm-demo 의 user_query 로 전달됨

Response 202

{
  "success": true,
  "data": {
    "session": { "session_id": "...", "status": "CHAT", "back_list_status": "not_started" }
  }
}
같은 세션에 이미 CHAT 추천이 돌고 있으면 409 Conflict.

3. 폴링

GET /v1/chat/{profile_id}/recommend/{session_id}
권장 폴링 간격 0.5 s. 응답 shape 은 status 에 따라 달라집니다.

Response — status: "CHAT" (진행 중)

{
  "success": true,
  "data": {
    "session_id": "...",
    "status": "CHAT",
    "back_list_status": "not_started",
    "updated_at": "...",
    "last_error": null
  }
}
폴링 계속.

Response — status: "READY" (완료)

{
  "success": true,
  "data": {
    "session_id": "...",
    "status": "READY",
    "back_list_status": "completed",
    "updated_at": "...",
    "last_error": null,
    "result": {
      "shopping_list": {
        "items": [
          {
            "item_name_en": "...",
            "price_yen": 380,
            "zone_name": "...",
            "id": 1,
            "matched": true,
            "product": {
              "id": 1,
              "name": "라무네 캔디 29g",
              "barcode": "4909254512030",
              "price": 1400,
              "price_unit": "₩",
              "section_code": "CK",
              "section_name": "계산대",
              "src_url": "https://cdn.ones1ght.com/store/product/no_image.png"
            }
          }
        ],
        "total_yen": 2450
      },
      "back_list": {
        "back_recommendations": [
          {
            "recommendation_id": "...",
            "item_name_en": "...",
            "price_yen": 180,
            "reason_type": "copurchase",
            "store_reasoning": { "method": "copurchase_lift", "scoring_equation": "..." }
          }
        ]
      }
    }
  }
}
완료 판정: status == "READY" AND back_list_status == "completed".

Response — status: "ERROR"

{
  "success": true,
  "data": {
    "session_id": "...",
    "status": "ERROR",
    "back_list_status": "not_started",
    "last_error": "upstream timeout",
    "result": { "shopping_list": null, "back_list": null }
  }
}
last_error 확인 후 새 추천을 kickoff 하거나 세션 종료. 참고: conversation_state / preferences / profile_context / meal / upsell_surface / timing 등 llm-demo 내부 필드는 응답에 포함되지 않습니다.

4. 세션 종료

DELETE /v1/chat/{profile_id}/session/{session_id}

Response 200

{
  "success": true,
  "data": {
    "session_id": "...",
    "ended": true,
    "ended_at": "2026-04-22T09:05:00Z",
    "reason": "explicit"
  }
}
명시 호출이 없어도 1 시간 비활동 이후 자동 종료됩니다.

에러 코드

HTTPcode원인
400INVALID_REQUESTbody 검증 실패
404NOT_FOUNDprofile / session 미존재 or 종료됨
409SESSION_NOT_STARTEDProfile 세션 시작 전 채팅 세션 생성 시도
409STAGE_NOT_CHATrecommend 호출 시 stamp 가 CHAT 아님
409CONFLICT같은 세션에 이미 CHAT 추천 진행 중
500INTERNAL_ERROR업스트림 장애 등

전체 예제

SDK_KEY="osk_..."
PROFILE_ID="..."

# 1. Profile 세션 시작
SESSION_ID=$(curl -s -X POST https://api.ones1ght.com/v1/profile/$PROFILE_ID/session/start \
  -H "Authorization: Bearer $SDK_KEY" | jq -r '.data.session_id')

# 2. LLM 채팅 세션 생성 (body 없음)
curl -X POST https://api.ones1ght.com/v1/chat/$PROFILE_ID \
  -H "Authorization: Bearer $SDK_KEY"

# 3. stamp CHAT 으로 전환
curl -X POST https://api.ones1ght.com/v1/profile/$PROFILE_ID/session/stamp \
  -H "Authorization: Bearer $SDK_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"CHAT"}'

# 4. 추천 kickoff
curl -X POST https://api.ones1ght.com/v1/chat/$PROFILE_ID/recommend \
  -H "Authorization: Bearer $SDK_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"session_id\":\"$SESSION_ID\",\"prompt\":\"오늘 저녁 카레 땡기는데\"}"

# 5. 폴링 (0.5s 간격)
while true; do
  RESP=$(curl -s https://api.ones1ght.com/v1/chat/$PROFILE_ID/recommend/$SESSION_ID \
    -H "Authorization: Bearer $SDK_KEY")
  STATUS=$(echo "$RESP" | jq -r '.data.status')
  [ "$STATUS" = "READY" ] && { echo "$RESP" | jq '.data.result'; break; }
  [ "$STATUS" = "ERROR" ] && { echo "$RESP" | jq '.data.last_error'; break; }
  sleep 0.5
done

# 6. 세션 종료
curl -X DELETE https://api.ones1ght.com/v1/chat/$PROFILE_ID/session/$SESSION_ID \
  -H "Authorization: Bearer $SDK_KEY"