Skip to main content

API로 플로우 작성 및 검증

v3 API에서 플로우 에이전트를 만들거나 수정할 때는 flow 필드를 사용합니다. flow는 외부 통합을 위한 공개 그래프 계약입니다.
flow_data는 기존 빌더 호환용 필드입니다. 새 통합은 flow를 사용하세요. flowflow_data를 함께 보내면 flow가 우선합니다.

필드 선택

필드상태사용 시점
flow권장새 플로우 생성, 전체 그래프 교체, API·SDK·MCP 기반 작성
flow_data지원 종료 예정기존 빌더 형태를 이미 저장하거나 읽는 통합의 호환 유지
둘 다 생략허용type="flow" 생성 시 기본 그래프를 서버가 만듭니다
둘 다 전송허용flow만 처리하고 flow_data는 검증 전에 무시합니다
flowflow_data는 모두 전체 그래프 교체입니다. 일부 필드만 보내서 그래프를 부분 수정하지 않습니다.
PATCH /v3/agents/{agent_id}에서 현재 그래프를 유지하려면 flow 필드를 생략하세요. flow: null은 명시적으로 거부됩니다.

그래프 구조

flownodesedges로 구성됩니다.
항목필수 값설명
nodes[].id필수그래프 안에서 유일한 노드 ID입니다
nodes[].type필수begin, conversation, condition, api, endCall 같은 노드 타입입니다
nodes[].position필수캔버스 좌표입니다. 서버가 좌표를 만들지 않습니다
nodes[].data선택노드별 설정입니다. 라우팅 키는 edges로 표현합니다
edges[].source필수출발 노드 ID입니다
edges[].target필수도착 노드 ID입니다
edges[].condition필수ai, logic, fallback 중 하나입니다
edges[].skip_user_response선택사용자 응답을 기다리지 않고 다음 노드로 이동할지 정합니다
nodes[].datatransitions, logicalTransitions, logical_transitions, globalNodeSettings, global_node_settings를 넣지 마세요. 이 값은 기존 빌더 내부 키입니다. flow에서는 edgesglobal_node_setting으로 표현합니다.

노드별 data 스키마

flow.nodesBeginFlowNode, ConversationFlowNode 같은 노드 타입별 스키마로 나뉩니다. nodes[].data도 노드 타입별 엄격한 스키마를 따릅니다. 문서에 없는 키를 보내면 FLOW_V2_INVALID로 거부됩니다. 작성할 때는 nodes[].type에 맞는 v2 data 스키마를 참고하세요. 예를 들어 beginBeginFlowNodeData, conversationConversationFlowNodeData, apiApiFlowNodeData, transferCallTransferCallFlowNodeData를 사용합니다. 스키마 레지스트리에서도 같은 계약을 확인할 수 있습니다.
스키마용도
/v3/schemas/flow-schema/flow-data전체 flow 그래프 스키마입니다
/v3/schemas/flow-schema/node-{type}해당 노드의 v2 래퍼와 data 스키마입니다
위치이름 규칙
flow.nodes, flow.edges, edge.conditionv3 API 기본 규칙인 snake_case를 사용합니다
edges[].skip_user_response기존 isSkipUserResponse 전환을 edges 필드로 올린 값입니다
nodes[].data.global_node_setting기존 globalNodeSettings를 대체하는 v2 글로벌 노드 표시입니다. conversation, sendSms, endCall에서만 허용됩니다
nodes[].data의 일반 노드 설정snake_case 키를 사용합니다. 예: first_line_type, prompt_type, tool_id, api_configuration, transfer_configuration
v2 flow는 라우팅과 글로벌 설정을 노드 밖으로 옮겼습니다. 기존 빌더(flow_data)에서 nodes[].data 안에 두던 키는 v2에서 위치가 아래처럼 바뀝니다.
기존 빌더(flow_data)의 node.datav2 flow에서의 표현
transitionsedges (분기 조건은 edge.condition)
logicalTransitions / logical_transitionscondition 노드 분기 → edge.conditionlogic
globalNodeSettings / global_node_settings (복수)nodes[].data.global_node_setting (단수 표시)
따라서 nodes[].data에는 위 빌더 내부 키를 넣지 않습니다. 넣으면 저장이 거부됩니다. 각 노드 타입의 정확한 data 필드 목록은 /v3/schemas/flow-schema/node-{type}에서 확인하세요. 노드별로 알아둘 점:
  • prompt_type/prompt/static_sentence (사전 멘트 모드 none/static/dynamic)는 conversation, api, tool, sendSms, transferCall, endCall에서 받습니다. transferCall의 warm 위스퍼 멘트는 별도 필드 (warm_transfer_prompt, warm_transfer_static_sentence)입니다.
  • transferAgentagent, preserve_chat_context만 받습니다. prompt는 없습니다.
  • conversation의 지식 베이스는 knowledge.rag_enabledknowledge.knowledge_ids로 설정합니다. 최상위 knowledge_ids는 받지 않습니다.
  • extraction의 추출 프롬프트는 extraction_configuration.extraction_prompt에 적습니다. 최상위 prompt는 받지 않습니다.
  • note는 에디터 주석 노드입니다. content, width, height만 받고 name은 받지 않으며, note로 향하거나 note에서 나가는 전환은 저장이 거부됩니다.

생성 예시

curl https://client-api.tryvox.co/v3/agents \
  -H "Authorization: Bearer $VOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "예약 확인 플로우",
    "type": "flow",
    "flow": {
      "nodes": [
        {
          "id": "begin",
          "type": "begin",
          "position": { "x": 0, "y": 0 },
          "data": {
            "name": "시작",
            "first_line_type": "aiFirst"
          }
        },
        {
          "id": "confirm",
          "type": "conversation",
          "position": { "x": 360, "y": 0 },
          "data": {
            "name": "예약 확인",
            "prompt_type": "dynamic",
            "prompt": "예약 정보를 확인하고 변경이 필요한지 물어보세요."
          }
        },
        {
          "id": "end",
          "type": "endCall",
          "position": { "x": 720, "y": 0 },
          "data": {
            "name": "종료",
            "prompt_type": "static",
            "static_sentence": "확인했습니다. 감사합니다."
          }
        }
      ],
      "edges": [
        {
          "source": "begin",
          "target": "confirm",
          "condition": { "type": "fallback" }
        },
        {
          "source": "confirm",
          "target": "end",
          "condition": {
            "type": "ai",
            "prompt": "사용자가 예약 확인을 마쳤을 때"
          }
        }
      ]
    }
  }'

전환 조건

edge.conditiontype으로 구분합니다.
자연어 조건입니다. 사용자의 발화와 현재 대화 맥락을 보고 다음 노드로 이동할지 판단합니다.
{
  "type": "ai",
  "prompt": "사용자가 상담원 연결을 요청했을 때"
}

글로벌 노드

글로벌 노드는 전환이 아니라 노드에 표시합니다. node.data.global_node_setting이 있으면 글로벌 노드로 처리합니다. global_node_settingconversation, sendSms, endCall 노드에서만 허용됩니다. 다른 노드 타입에 넣으면 저장이 거부됩니다(웹 빌더도 이 세 타입에서만 글로벌 노드를 지원합니다).
{
  "id": "human-help",
  "type": "conversation",
  "position": { "x": 360, "y": 240 },
  "data": {
    "name": "상담원 연결 안내",
    "prompt_type": "dynamic",
    "prompt": "상담원 연결 절차를 안내하세요.",
    "global_node_setting": {
      "condition": {
        "type": "ai",
        "prompt": "사용자가 사람 상담원을 원할 때"
      }
    }
  }
}
글로벌 노드의 조건은 ai만 지원합니다. logic이나 fallback은 저장할 수 없습니다.

저장 검증

flow 저장은 자동 수정 없이 검증합니다. 불완전한 그래프를 서버가 추측해서 고치지 않습니다. 저장 전에 같은 flow 그래프를 서버에 저장하지 않고 검증하려면 POST /v3/agents/validate-flow를 호출합니다.
curl "https://client-api.tryvox.co/v3/agents/validate-flow?level=all" \
  -H "Authorization: Bearer $VOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": {
      "nodes": [
        {
          "id": "begin",
          "type": "begin",
          "position": { "x": 0, "y": 0 },
          "data": {
            "name": "시작",
            "first_line_type": "aiFirst"
          }
        },
        {
          "id": "end",
          "type": "endCall",
          "position": { "x": 320, "y": 0 },
          "data": {
            "name": "종료"
          }
        }
      ],
      "edges": [
        {
          "source": "begin",
          "target": "end",
          "condition": { "type": "fallback" }
        }
      ]
    }
  }'
응답 필드의미
valid저장을 막는 치명적 오류가 없으면 true입니다
errors저장을 막는 치명적 오류 목록입니다
advisories저장은 가능하지만 실행 중 동작이 예상과 달라질 수 있는 런타임 주의 항목 목록입니다
validate-flow는 저장하지 않고 검증하므로 형식이 잘못된 flow도 일반 에러 응답 대신 valid=false 엔벨로프로 돌려줍니다. 예를 들어 position 누락, 잘못된 condition.type, 지원하지 않는 logic 연산자는 errors[].code = "flow_v2_schema_invalid"로 반환됩니다. level 쿼리로 응답에 포함할 항목 범위를 정할 수 있습니다.
level반환 내용
critical기본값입니다. 저장을 막는 errors만 반환합니다
runtimeadvisories만 반환합니다. valid는 치명적 오류 여부를 계속 반영합니다
allerrorsadvisories를 모두 반환합니다
치명적 오류가 있는 그래프라도 변환 가능한 경우에는 런타임 주의 항목을 함께 반환합니다. 그래서 level=runtime에서는 errors가 비어 있어도 valid=false일 수 있습니다. level=all에서는 저장을 막는 오류와 런타임 주의 항목을 함께 확인할 수 있습니다. 런타임 주의 항목에는 연결되지 않은 skip/fallback 전환이나 begin에서 도달 가능한 종료 노드가 없는 경우가 포함됩니다. 이런 항목은 저장을 막지 않지만, 실제 통화 실행 전에 수정하는 것이 좋습니다. 도구, 지식 베이스, 파일, 다른 에이전트 이관처럼 외부 리소스를 참조하는 필드는 값을 보냈다면 실제 존재 여부와 조직 접근 권한을 검증합니다. 비어 있는 참조는 작성 중인 초안으로 저장할 수 있지만, 잘못된 ID나 다른 조직의 ID는 저장이 거부됩니다. 런타임 주의 항목이 있는 그래프라도 이 참조 검증은 생략되지 않습니다.
상황결과
nodes 또는 edges 누락저장 거부
position 누락저장 거부
begin.data.first_line_type 누락저장 거부
begin 노드가 0개 또는 2개 이상저장 거부
begin 노드에 fallback 전환 없음저장 거부
begin에서 fallback이 아닌 조건 사용저장 거부
begin에서 skip_user_response=true 사용저장 거부
전환의 source 또는 target이 존재하지 않는 노드 ID저장 거부
노드 ID 또는 전환 ID 중복저장 거부
logic 전환이 조건 노드가 아닌 곳에서 출발저장 거부
logic 조건의 equations가 비어 있음저장 거부
지원하지 않는 logic 연산자 사용저장 거부
sourcefallback 전환이 2개 이상저장 거부
같은 source에 같은 조건 전환이 2개 이상저장 거부
global_node_setting이 객체가 아니거나 비어 있거나 ai 조건이 아님저장 거부
conversation/sendSms/endCall이 아닌 노드에 global_node_setting 포함저장 거부
note 노드에 연결된 전환(source 또는 target이 note)저장 거부
transitions, logicalTransitions, logical_transitions, globalNodeSettings, global_node_settings 포함저장 거부
문서화되지 않은 nodes[].data 최상위 키 포함저장 거부
제공한 도구, 지식 베이스, 파일, 이관 대상 에이전트 참조가 없거나 접근 불가저장 거부
function 또는 기존 knowledge 노드 포함flow 쓰기 거부
오래된 그래프를 조회하면 flow에 표시되지 않는 빌더 내부 분기가 있을 수 있습니다. 이런 그래프는 flow로 다시 저장할 때 거부될 수 있습니다. 기존 빌더 형태를 정리한 뒤 다시 저장하세요.

지원 종료 예정 경로

새 통합에서는 아래 경로를 사용하지 마세요.
  • flow_data: 기존 빌더 그래프입니다. 읽기와 쓰기는 호환용으로만 유지됩니다.
  • POST /v3/agents/validate-flow-data: flow_data 전용 검증입니다. flow 검증은 POST /v3/agents/validate-flow를 사용합니다.
  • POST /v3/agents/autofix-flow-data: flow_data 보정 도구입니다.
  • POST /v3/flow-data/autofix: flow_data 보정 도구입니다.
  • POST /v3/agents/{agent_id}/operations: 기존 빌더 그래프를 diff 방식으로 수정합니다.
  • sourceHandle, targetHandle, transitions, logicalTransitions, globalNodeSettings: flow 작성에는 사용하지 않습니다.

마이그레이션

1

조회 코드를 flow로 전환

GET /v3/agents/{agent_id} 응답에서 flow_data 대신 flow를 읽습니다.
2

작성 코드를 flow로 전환

POST /v3/agentsPATCH /v3/agents/{agent_id}에서 flow를 보냅니다. flow_data는 보내지 않습니다.
3

검증 루틴 정리

validate-flow-dataautofix-flow-data 호출을 제거합니다. 저장 전 검증이 필요하면 POST /v3/agents/validate-flow를 사용합니다.
4

빌더 내부 키 제거

sourceHandle, transitions, globalNodeSettings 같은 내부 키를 제거하고 edges[].conditionglobal_node_setting으로 바꿉니다.
5

노드 data 키를 snake_case로 전환

firstLineType, promptType, apiConfiguration 같은 키를 first_line_type, prompt_type, api_configuration으로 바꿉니다.

LLM 작성 체크리스트

LLM이나 MCP 클라이언트가 flow를 직접 작성할 때는 아래 순서로 payload를 조립하세요.
  1. flow_data 대신 flow만 사용합니다.
  2. 모든 노드에 id, type, position을 넣습니다.
  3. begin 노드에는 data.first_line_type을 넣고, begin에서 나가는 전환은 fallback 하나로 둡니다.
  4. 전환은 edges[].condition.typeai, logic, fallback 중 하나로 표현합니다.
  5. logic 조건은 조건 노드에서만 시작하게 하고, equations를 하나 이상 넣습니다.
  6. node.data에는 snake_case 키만 사용합니다.
  7. node.data에는 transitions, logicalTransitions, globalNodeSettings를 넣지 않습니다.
  8. 저장 전에 POST /v3/agents/validate-flow?level=all을 호출해 errors를 모두 해결합니다.

다음 단계

전환 조건

대시보드에서 전환 조건을 설계하는 방법을 확인하세요.

v3 API 참조

에이전트 생성과 수정 엔드포인트의 전체 스키마를 확인하세요.

flow, flow_data deprecated, 플로우 API, 플로우 작성, 플로우 검증, validate-flow, edge condition, global_node_setting, sourceHandle, transitions, validate-flow-data, autofix-flow-data