Prosody

AICC · 에이전트 API

AICC Runtime API

게시한 에이전트에 사용자 메시지와 최근 대화 상태를 전달하고 JSON 또는 SSE로 답변을 받습니다.

1

에이전트 대화

API Key와 Agent ID는 서버에만 보관하고 브라우저에서는 고객 서버 프록시를 호출하세요.

URL

POST
https://console.humelo.com/api/v1/agents/chat

인증 및 헤더

API Key는 서버 환경변수에 보관하고 요청 헤더로만 전달하세요.

http
Authorization: Bearer {YOUR_API_KEY}
Content-Type: application/json
Accept: application/json # SSE는 text/event-stream

요청 필드

  • agent_idUUID필수

    호출할 에이전트 ID입니다. 에이전트 빌더에서 확인할 수 있습니다.

  • messagestring조건부

    이번 턴의 사용자 입력입니다. 생략하거나 공백이면 history 또는 messages의 마지막 비어 있지 않은 user 메시지를 사용합니다.

    대체할 user 메시지가 없으면 E4201/400; 최대 4,000자

  • session_idstring선택

    운영 로그에서 같은 상담을 묶을 고객 측 세션 ID입니다.

    영문, 숫자, ., _, :, -만 사용; 1–160자

  • historyTurn[]선택

    최근 대화입니다. 각 항목은 role과 content를 가지며 messages보다 우선합니다.

    기본값 [] · 마지막 16턴 사용; role은 user 또는 assistant; content는 턴당 최대 4,000자

  • messagesTurn[]선택

    history와 같은 형식의 별칭입니다. history가 없을 때만 사용됩니다.

    기본값 [] · 마지막 16턴 사용

  • stateobject | null선택

    이전 응답의 state를 그대로 전달하면 멀티턴 상태가 이어집니다.

    기본값 null · JSON 문자열 기준 최대 16,000자

  • streamboolean선택

    true면 Server-Sent Events로 응답합니다. Accept 헤더로도 활성화할 수 있습니다.

    기본값 false

요청 예시

json
{
  "agent_id": "00000000-0000-0000-0000-000000000000",
  "message": "예약 취소 수수료가 어떻게 되나요?",
  "session_id": "customer-42:chat-7",
  "history": [],
  "state": null,
  "stream": false
}

응답

200

JSON 응답

  • agent_idUUID필수

    응답한 에이전트 ID입니다.

  • agent_namestring필수

    에이전트 이름입니다.

  • responsestring필수

    최종 답변입니다.

  • matched_intentstring | null필수

    매칭된 의도 이름입니다.

  • handoff_requiredboolean필수

    상담원 연결이 필요한지 나타냅니다.

  • retrieved_contextobject[]필수

    답변에 사용한 지식 항목입니다.

  • actionsobject[]필수

    실행한 에이전트 액션입니다.

  • stateobject필수

    다음 요청에 다시 보낼 멀티턴 상태입니다.

  • end_callboolean필수

    음성 채널에서 통화 종료가 필요한지 나타냅니다.

  • runtimeobject필수

    응답 채널 메타데이터입니다.

JSON 응답
{
  "agent_id": "00000000-0000-0000-0000-000000000000",
  "agent_name": "라온투어 고객센터",
  "response": "예약 조건에 따라 취소 수수료가 달라질 수 있습니다.",
  "matched_intent": "패키지 취소료 기준",
  "handoff_required": false,
  "retrieved_context": [],
  "actions": [],
  "state": { "topic": "cancellation_fee", "handoff": false },
  "end_call": false,
  "runtime": { "mode": "text", "voice_engine": "DIVE" }
}
200

SSE 응답

stream이 true이거나 Accept가 text/event-stream이면 start, chunk, 선택적인 tool_call, done 순서로 전송됩니다. 실패 시 error 이벤트로 종료됩니다.

Response headers
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform
X-Accel-Buffering: no
  • startevent필수

    의도, 핸드오프, 검색 지식, 초기 state입니다.

  • chunkevent필수

    화면에 이어 붙일 delta 문자열입니다.

  • tool_callevent선택

    도구 실행이 공개될 때의 이름과 인자입니다.

  • doneevent필수

    사용량 정산까지 성공한 뒤 보내는 최종 response, actions, state, end_call입니다.

  • errorevent조건부

    스트림 처리 실패 시 오류 메시지입니다.

400

E4201 · 잘못된 요청

agent_id가 없거나, message와 history/messages의 user 입력이 모두 비어 있거나, 필드 형식이 잘못된 경우입니다. 사용량 예약·과금·답변 생성 전에 거절됩니다.

E4201 · 잘못된 요청
{
  "error": "message or a user message in history is required",
  "code": "E4201"
}
401

E4001 / E4002 · 인증 오류

Bearer API Key가 없거나 유효하지 않습니다.

402

E4601 · 크레딧 부족

최대 예상 사용량을 예약할 크레딧이 부족합니다.

404

E4301 · 에이전트 없음

API Key 조직에서 agent_id를 찾을 수 없습니다.

409

E4302 · 게시 버전 없음

에이전트에 사용할 수 있는 게시 버전이 없습니다.

413

E4204 · 요청 크기 초과

요청 body 또는 state가 허용 크기를 초과했습니다.

429

E4403 · 호출 제한 초과

API Key 기준 분당 600회 제한을 초과했습니다.

500 / 503

E5001 / E5002 / E5003 · 서버 오류, 일시적 서비스 불가, 처리 제한 시간 초과

의존 서비스 불가·과부하·사용할 수 없는 응답은 E5002/503이며 backoff 후 제한적으로 재시도할 수 있습니다. 턴 처리 제한 시간 초과는 E5003/500, 그 밖의 예상치 못한 오류는 E5001/500입니다. 실패한 요청의 최대 예약분은 정산 전에 환급되며, SSE는 정산 실패 시 done 대신 error 이벤트로 종료됩니다.

2

상담 목록

에이전트의 전화·웹 위젯·API 상담을 시작 시각 최신순으로 조회합니다. 통계는 이 목록과 요약 값으로 직접 만듭니다. 테스트 대화는 포함하지 않습니다. '상담 조회 허용'을 켠 API Key만 부를 수 있습니다.

URL

GET
https://console.humelo.com/api/v1/agents/{agent_id}/consultations

인증 및 헤더

API Key는 서버 환경변수에 보관하고 요청 헤더로만 전달하세요.

http
Authorization: Bearer {YOUR_API_KEY}

경로 파라미터

  • agent_idUUID필수

    API Key 조직의 에이전트 ID입니다.

Query

  • fromRFC 3339선택

    이 시각 이후 시작한 상담부터 조회합니다.

    기본값 to의 30일 전

  • toRFC 3339선택

    이 시각 전에 시작한 상담까지 조회합니다.

    기본값 지금 · from과 최대 92일

  • channelstring선택

    phone, web_widget, api 중 하나로 거릅니다.

  • statusstring선택

    ai_handling, handoff_requested, agent_active, resolved 중 하나로 거릅니다.

  • limitinteger선택

    한 번에 받을 상담 수입니다.

    기본값 20 · 1~100

  • cursorstring선택

    이전 응답의 next_cursor입니다. 같은 기간·조건으로 다음 쪽을 받습니다.

요청 예시

bash
curl "https://console.humelo.com/api/v1/agents/{agent_id}/consultations?from=2026-10-01T00:00:00%2B09:00&channel=phone&limit=50" \
  -H "Authorization: Bearer $HUMELO_API_KEY"

응답

200

목록 응답

  • consultationsobject[]필수

    상담 목록입니다. 항목 필드는 아래 상담 필드와 같습니다.

  • next_cursorstring | null필수

    다음 쪽이 있으면 cursor로 보낼 값, 없으면 null입니다.

  • idUUID필수

    상담 ID입니다. 상세 조회에 씁니다.

  • channelstring필수

    phone, web_widget, api(카카오톡 채널 포함) 중 하나입니다.

  • statusstring필수

    ai_handling, handoff_requested, agent_active, resolved 중 하나입니다.

  • titlestring | null필수

    상담 제목입니다.

  • started_atISO 8601필수

    상담 시작 시각입니다. 목록 기간과 정렬의 기준입니다.

  • last_message_atISO 8601필수

    마지막 메시지 시각입니다.

  • handoff_requestedboolean필수

    상담원 연결이 필요했던 상담인지 나타냅니다.

  • purgedboolean필수

    보관 기간이 지나 내용을 파기한 상담이면 true입니다. 이때 title·summary·발신번호·대화·접수는 비어 있습니다.

  • callobject조건부

    전화 상담의 caller_number, started_at, ended_at, duration_seconds입니다.

    channel=phone일 때만

  • summaryobject | null필수

    상담 요약입니다. 웹훅 conversation.summary의 data와 같은 모양(summary, customer_intent, resolution_status, quality_score, quality_reason, system, custom_fields 등)이며 요약이 아직 없으면 null입니다.

목록 응답
{
  "consultations": [
    {
      "id": "6f1c2a4e-0d7b-4c51-9a3e-2b9f8c7d6e5a",
      "channel": "phone",
      "status": "resolved",
      "title": "충전 금액 문의",
      "started_at": "2026-10-29T01:12:03.512Z",
      "last_message_at": "2026-10-29T01:14:40.118Z",
      "handoff_requested": false,
      "purged": false,
      "call": {
        "caller_number": "01012345678",
        "started_at": "2026-10-29T01:12:01Z",
        "ended_at": "2026-10-29T01:14:45Z",
        "duration_seconds": 164
      },
      "summary": {
        "summary": "고객이 최근 충전 금액을 문의해 조회 결과를 안내했습니다.",
        "customer_intent": "충전 금액 문의",
        "resolution_status": "resolved",
        "quality_score": 9
      }
    }
  ],
  "next_cursor": null
}
400

E4201 · 잘못된 요청

기간·채널·상태·limit·cursor 값이 형식에 맞지 않습니다.

401

E4001 / E4002 · 인증 오류

Bearer API Key가 없거나 유효하지 않습니다.

403

E4101 · 권한 없음

API Key에 '상담 조회 허용'이 꺼져 있거나 공공 구성 조직의 키입니다. 상담 조회 허용은 API 키 화면에서 조직 대표가 키마다 켭니다. 공공 구성 조직은 외부 도구 연결과 같이 상담 기록을 API로 가져갈 수 없습니다.

404

E4301 · 에이전트 또는 상담 없음

API Key 조직에서 에이전트를 찾을 수 없거나, 그 에이전트의 상담이 아닙니다.

429

E4403 · 호출 제한 초과

API Key 기준 조회 분당 600회 제한을 초과했습니다. 대화 API와 따로 셉니다.

503

E5002 · 일시적 서비스 불가

상담 기록을 일시적으로 읽을 수 없습니다. backoff 후 다시 시도하세요.

3

상담 상세

상담 하나와 고객·AI·상담원 대화, 고객 요청 접수를 조회합니다. 내부 메모와 시스템 이벤트는 포함하지 않습니다.

URL

GET
https://console.humelo.com/api/v1/agents/{agent_id}/consultations/{consultation_id}

인증 및 헤더

API Key는 서버 환경변수에 보관하고 요청 헤더로만 전달하세요.

http
Authorization: Bearer {YOUR_API_KEY}

경로 파라미터

  • agent_idUUID필수

    API Key 조직의 에이전트 ID입니다.

  • consultation_idUUID필수

    목록의 상담 ID입니다.

응답

200

상세 응답

  • consultationobject필수

    목록 항목과 같은 상담 필드입니다.

  • messagesobject[]필수

    role(customer 고객, ai AI, counselor 상담원, notice 고객이 본 상담원 연결 안내), content, created_at을 시각순으로 담습니다.

  • receptionsobject[]필수

    고객 요청 접수의 id, status, reason, fields(접수한 정보), requested_at, resolved_at입니다.

상세 응답
{
  "consultation": {
    "id": "6f1c2a4e-0d7b-4c51-9a3e-2b9f8c7d6e5a",
    "channel": "phone",
    "status": "resolved",
    "title": "충전 금액 문의",
    "started_at": "2026-10-29T01:12:03.512Z",
    "last_message_at": "2026-10-29T01:14:40.118Z",
    "handoff_requested": false,
    "purged": false,
    "call": {
      "caller_number": "01012345678",
      "started_at": "2026-10-29T01:12:01Z",
      "ended_at": "2026-10-29T01:14:45Z",
      "duration_seconds": 164
    },
    "summary": {
      "summary": "고객이 최근 충전 금액을 문의해 조회 결과를 안내했습니다.",
      "customer_intent": "충전 금액 문의",
      "resolution_status": "resolved",
      "quality_score": 9
    }
  },
  "messages": [
    { "role": "customer", "content": "최근 충전 금액 알려 주세요.", "created_at": "2026-10-29T01:12:05.201+00:00" },
    { "role": "ai", "content": "최근 충전 금액은 3만 원입니다.", "created_at": "2026-10-29T01:12:09.880+00:00" }
  ],
  "receptions": []
}
400

E4201 · 잘못된 요청

기간·채널·상태·limit·cursor 값이 형식에 맞지 않습니다.

401

E4001 / E4002 · 인증 오류

Bearer API Key가 없거나 유효하지 않습니다.

403

E4101 · 권한 없음

API Key에 '상담 조회 허용'이 꺼져 있거나 공공 구성 조직의 키입니다. 상담 조회 허용은 API 키 화면에서 조직 대표가 키마다 켭니다. 공공 구성 조직은 외부 도구 연결과 같이 상담 기록을 API로 가져갈 수 없습니다.

404

E4301 · 에이전트 또는 상담 없음

API Key 조직에서 에이전트를 찾을 수 없거나, 그 에이전트의 상담이 아닙니다.

429

E4403 · 호출 제한 초과

API Key 기준 조회 분당 600회 제한을 초과했습니다. 대화 API와 따로 셉니다.

503

E5002 · 일시적 서비스 불가

상담 기록을 일시적으로 읽을 수 없습니다. backoff 후 다시 시도하세요.

연동 흐름

에이전트 빌더

문서와 지침으로 에이전트 지식과 응대 방식을 만들고 검수합니다.

1단계

배포

검수한 에이전트 지식을 런타임에서 사용할 버전으로 게시합니다.

2단계

API Key 발급

서버에서 사용할 API Key와 Agent ID를 안전하게 보관합니다.

3단계

서버 프록시 연결

브라우저와 앱은 고객 서버를 호출하고 고객 서버가 Prosody를 호출합니다.

4단계

스트리밍 요청

채팅 UI에서는 SSE chunk의 delta를 이어 붙이고, done 이벤트의 state를 저장해 다음 요청에 다시 보내세요.

SSE request
curl https://console.humelo.com/api/v1/agents/chat \
  -N \
  -H "Authorization: Bearer ${PROSODY_API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "agent_id": "00000000-0000-0000-0000-000000000000",
    "message": "환불은 얼마나 걸리나요?",
    "session_id": "customer-42:chat-7",
    "stream": true
  }'

서버 프록시 패턴

private API Key는 브라우저에 넣지 않습니다. 브라우저는 고객 서버를 호출하고 고객 서버가 Prosody API를 호출합니다.

Next.js route handler
// app/api/agent/chat/route.ts
export async function POST(request: Request) {
  const body = await request.json();

  const response = await fetch("https://console.humelo.com/api/v1/agents/chat", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.PROSODY_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      agent_id: process.env.PROSODY_AGENT_ID,
      message: body.message,
      session_id: body.sessionId,
      history: body.history ?? [],
      state: body.state ?? null,
      stream: false,
    }),
  });

  return new Response(await response.text(), {
    status: response.status,
    headers: {
      "Content-Type": response.headers.get("Content-Type") ?? "application/json",
    },
  });
}
Browser widget state
type Turn = { role: "user" | "assistant"; content: string };

let history: Turn[] = [];
let state: Record<string, unknown> | null = null;

async function sendToAgent(message: string) {
  const response = await fetch("/api/agent/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message, history, state }),
  });

  if (!response.ok) throw new Error("Agent is temporarily unavailable");

  const result = await response.json();
  history = [
    ...history,
    { role: "user", content: message },
    { role: "assistant", content: result.response },
  ].slice(-16);
  state = result.state ?? state;
  return result;
}

멀티턴 상태

  • 최근 8~16턴 정도의 history를 보냅니다.
  • 응답의 state를 고객 상담 세션 단위로 저장합니다.
  • 새 상담을 시작할 때 history와 state를 초기화합니다.

운영 체크리스트

  • API Key는 서버 환경변수나 secret manager에만 둡니다.
  • 프록시에 자체 인증, origin, rate limit 정책을 둡니다.
  • 고객 정보 저장 정책에 맞춰 transcript를 마스킹합니다.
LLM/Agent용 문서

화면과 같은 계약을 그대로 전달할 수 있습니다.

문서 복사 메뉴의 현재 문서, 전체 문서, ChatGPT/Claude 전달 기능은 이 페이지의 동일한 계약 데이터를 사용합니다.