메인 콘텐츠로 건너뛰기
이 API는 Client SDK 키(osk_ 접두사)로 인증합니다. REST API 채팅(OpenAI 호환)과는 별도의 엔드포인트입니다.

메시지 전송

POST /v1/chat/{persona_id}
페르소나에게 메시지를 전송합니다. thread_id를 생략하면 새 스레드가 생성되고, 포함하면 기존 스레드를 이어갑니다. 사용 가능한 모델은 GET /v1/models로 조회할 수 있습니다.

요청 — 새 스레드

{
  "model": "12d10e3e-9ce7-47f9-9f84-45d22ebb496a",
  "messages": [
    {
      "role": "user",
      "content": "오늘 저녁은 뭐 먹으면 좋을까?"
    }
  ]
}

요청 — 기존 스레드 이어가기

{
  "thread_id": "thr_a1b2c3d4e5f6",
  "messages": [
    {
      "role": "user",
      "content": "카레 재료 알려줘"
    }
  ]
}
필드타입필수설명
modelstring새 스레드 시 필수모델 ID (GET /v1/modelsid 값)
thread_idstringX기존 스레드 ID (생략 시 새 스레드 생성)
messagesarrayO메시지 배열
messages[].rolestringOuser
messages[].contentstringO메시지 내용
streambooleanX스트리밍 여부 (기본: false)
새 스레드 생성 시 지정한 모델이 해당 스레드에 고정됩니다. 이후 대화에서는 model 필드를 생략해도 동일한 모델이 사용됩니다.

응답

{
  "success": true,
  "data": {
    "thread_id": "thr_a1b2c3d4e5f6",
    "is_new_thread": true,
    "user_message": {
      "message_id": "msg_u1v2w3x4y5z6",
      "role": "user",
      "content": "오늘 저녁은 뭐 먹으면 좋을까?",
      "created_at": "2026-04-16T10:00:00Z"
    },
    "assistant_message": {
      "message_id": "msg_a7b8c9d0e1f2",
      "role": "assistant",
      "blocks": [
        {
          "type": "text",
          "content": "비가 오는 날엔 따뜻한 소고기 카레는 어떠세요?"
        },
        {
          "type": "product_list",
          "title": "매콤 소고기 카레 재료",
          "badge": "AI 추천",
          "items": [
            { "id": "p_001", "name": "한우 등심 (300g)", "section": "정육 코너", "price": 24500 },
            { "id": "p_002", "name": "유기농 감자/당근 세트", "section": "신선 채소", "price": 4800 }
          ],
          "actions": [
            { "id": "view_recipe", "label": "자세한 내용 보기", "style": "primary" },
            { "id": "show_alternates", "label": "다른 추천 보기", "style": "secondary" }
          ]
        },
        {
          "type": "suggestion",
          "content": "카레와 함께 곁들일 레드 와인도 추천해 드릴까요?",
          "actions": [
            { "id": "wine_yes", "label": "추천받기", "style": "primary" },
            { "id": "wine_no", "label": "괜찮아요", "style": "secondary" }
          ]
        }
      ],
      "created_at": "2026-04-16T10:00:01Z"
    },
    "credits": {
      "used": 289,
      "balance": 149.50
    }
  }
}

블록 타입

assistant 응답은 구조화된 blocks 배열로 반환됩니다.
타입설명주요 필드
text텍스트 메시지content
image이미지url
product_list상품 목록title, items[], actions[]
suggestionAI 추천/제안content, actions[]

액션

블록에 포함된 actions는 클라이언트에서 사용자 인터랙션을 처리하기 위한 정보입니다.
필드설명
id액션 식별자
label버튼 텍스트
styleprimary / secondary / text

스레드 조회

GET /v1/chat/{persona_id}/threads/{thread_id}
스레드의 메타 정보를 조회합니다 (메시지 본문은 미포함).

응답

{
  "success": true,
  "data": {
    "thread_id": "thr_a1b2c3d4e5f6",
    "title": "오늘 저녁 메뉴 추천",
    "status": "ACTIVE",
    "message_count": 4,
    "started_at": "2026-04-16T10:00:00Z",
    "last_active_at": "2026-04-16T10:30:00Z"
  }
}
상태설명
ACTIVE진행 중
CLOSED종료됨

스레드 종료

POST /v1/chat/{persona_id}/threads/{thread_id}/close
스레드를 종료합니다. 페르소나 상태가 CHATREADY로 전환됩니다.

응답

{
  "success": true,
  "data": {
    "thread_id": "thr_a1b2c3d4e5f6",
    "thread_status": "CLOSED",
    "persona_status": "READY",
    "closed_at": "2026-04-16T10:35:00Z"
  }
}
이미 종료된 스레드에 요청하면 409 Conflict가 반환됩니다:
{
  "success": false,
  "error": {
    "code": "ALREADY_CLOSED",
    "message": "thread is already closed"
  }
}

메시지 목록 조회

GET /v1/chat/{persona_id}/threads/{thread_id}/messages
스레드의 메시지 목록을 조회합니다 (오래된 순). 커서 기반 페이지네이션을 지원합니다.

쿼리 파라미터

파라미터타입기본값설명
limitinteger50반환할 메시지 수 (최대 100)
beforestring-이 message_id 이전 메시지 로드 (역방향 페이징)

응답

{
  "success": true,
  "data": {
    "thread_id": "thr_a1b2c3d4e5f6",
    "messages": [
      {
        "message_id": "msg_u1v2w3x4y5z6",
        "role": "user",
        "content": "오늘 저녁은 뭐 먹으면 좋을까?",
        "created_at": "2026-04-16T10:00:00Z"
      },
      {
        "message_id": "msg_a7b8c9d0e1f2",
        "role": "assistant",
        "blocks": [
          { "type": "text", "content": "소고기 카레는 어떠세요?" }
        ],
        "created_at": "2026-04-16T10:00:01Z"
      }
    ],
    "has_more": false,
    "next_before": null
  }
}
has_moretrue이면 next_before 값을 before 파라미터로 전달하여 다음 페이지를 로드합니다.

전체 흐름 예제

# 1. 페르소나 생성
PERSONA_ID=$(curl -s -X POST https://api.ones1ght.com/v1/persona \
  -H "Authorization: Bearer $SDK_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "홍길동", "locale": "ko"}' | jq -r '.data.persona_id')

# 2. 모델 목록 조회 → 첫 번째 모델 ID 사용
MODEL_ID=$(curl -s https://api.ones1ght.com/v1/models \
  -H "Authorization: Bearer $SDK_KEY" | jq -r '.data[0].id')

# 3. 채팅 시작 (새 스레드 — model 필수)
THREAD_ID=$(curl -s -X POST https://api.ones1ght.com/v1/chat/$PERSONA_ID \
  -H "Authorization: Bearer $SDK_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\": \"$MODEL_ID\", \"messages\": [{\"role\": \"user\", \"content\": \"오늘 저녁 뭐 먹을까?\"}]}" | jq -r '.data.thread_id')

# 4. 대화 이어가기 (model 생략 — 스레드에 고정됨)
curl -X POST https://api.ones1ght.com/v1/chat/$PERSONA_ID \
  -H "Authorization: Bearer $SDK_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"thread_id\": \"$THREAD_ID\", \"messages\": [{\"role\": \"user\", \"content\": \"카레 재료 알려줘\"}]}"

# 5. 메시지 이력 조회
curl https://api.ones1ght.com/v1/chat/$PERSONA_ID/threads/$THREAD_ID/messages \
  -H "Authorization: Bearer $SDK_KEY"

# 6. 스레드 종료
curl -X POST https://api.ones1ght.com/v1/chat/$PERSONA_ID/threads/$THREAD_ID/close \
  -H "Authorization: Bearer $SDK_KEY"