Jenova 에이전트 API 참조
기본 URL: https://api.jenova.ai/v1
인증: Authorization 헤더에 Bearer 토큰 사용
목차
개요
몇 분 만에 맞춤형 에이전트를 제품이나 워크플로에서 실행하세요. 어떤 작업에든 맞게 에이전트를 설정하고, 모델과 도구는 자유롭게 선택하세요. 에이전트 하네스, 데이터베이스, 확장은 Jenova가 처리합니다.
완전한 에이전트 스택:
- 관리형 에이전트 하네스: 호출은 한 번, 결과물은 완성됩니다. 에이전트가 조사하고 추론하고 도구를 호출하며 파일까지 생성합니다 — 지시하는 대로 정확히 수행합니다.
- 무한한 컨텍스트와 메모리: RAG 기반 컨텍스트 관리와 독자적인 세션 상태 추적이 하나의 대화 안에서 무제한 메모리를 가능하게 합니다.
- 도구와 MCP 라이브러리: 검색, 이미지 생성, 이메일 등 30개 이상의 도구와 MCP 서버로 구성된 라이브러리에 연결하거나, 자체 MCP 서버를 직접 연결할 수도 있습니다.
- 어떤 모델로든 매끄럽게 전환: OpenAI, Anthropic, Google, xAI 또는 주요 오픈소스 제공업체의 모델을 배포하고, 파라미터 하나만 바꿔 모델 간에 전환할 수 있습니다.
- 관리형 지식과 RAG: Jenova가 엔드투엔드 RAG 파이프라인을 처리합니다 — 청킹, 인덱싱, 저장, 검색까지.
- 대규모 운영에서 검증됨: 수백 개의 에이전트가 실제 프로덕션에서 운영되는 실전 검증된 인프라 위에 배포하세요. 프로비저닝, 확장, 유지 관리할 클러스터가 전혀 없습니다.
빠른 시작
1. API 키 받기
www.jenova.ai/platform의 개발자 대시보드에서 API 키를 생성합니다. 키는 jnv_sk_* 형식을 사용하며 Bearer 토큰으로 전달됩니다.
2. 에이전트 선택 또는 생성
플랫폼에서 사전 구축된 에이전트를 선택하거나, 대시보드에서 지침, 모델 설정, 지식 베이스 파일, 도구, MCP 서버를 지정하여 커스텀 에이전트를 생성합니다.
3. 첫 메시지 보내기
세션을 생성하고 한 번의 호출로 메시지를 보냅니다:
curl -N -X POST https://api.jenova.ai/v1/messages \
-H "Authorization: Bearer jnv_sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"agent": "my-support-agent",
"user": "user_12345",
"content": "What can you help me with?"
}'
응답은 Server-Sent Events로 스트리밍되어 돌아옵니다:
event: stream_started
data: {"session_id":"ses_xyz789","run_id":"run_abc123","agent":"my-support-agent"}
event: stream_delta
data: {"session_id":"ses_xyz789","run_id":"run_abc123","chunk_content":"I can help you with ","seq":1}
event: stream_ended
data: {"session_id":"ses_xyz789","run_id":"run_abc123","success":true,"stop_reason":"end_run","usage":{"cost":"0.0032"}}
후속 요청을 위해 stream_started에서 session_id를 확보하세요. 동기식 JSON 응답에 대해서는 메시지 보내기를 참조하세요.
핵심 개념
에이전트
API를 통해 상호작용하는 AI 에이전트입니다. 각 에이전트는 API 호출에서 agent 값으로 사용되는 고유한 slug(예: my-support-agent)를 가집니다.
- 사전 구축: 플랫폼에 있는 기존 에이전트 중에서 선택합니다.
- 커스텀: 대시보드에서 지침, 모델, 지식 베이스, 도구, MCP 서버를 지정하여 직접 구성합니다.
세션
최종 사용자와 에이전트 간의 독립적인 대화 스레드입니다.
- 식별자: 접두사가 붙은 ID(예:
ses_abc123). - 범위: 동일한 에이전트와 최종 사용자에 대해 여러 세션이 존재할 수 있으며, 각 세션은 독립적인 대화 상태를 가집니다.
- 수명 주기: 세션은 API를 통해 삭제되기 전까지 무기한 유지됩니다. 세션이 필요 없는 일회성 작업의 경우
ephemeral: true와 함께POST /messages를 사용하세요. - 플랫폼 분리: API 세션은 Jenova 웹 앱의 대화와 별개입니다. 최종 사용자, 세션 기록, 결제는 API와 웹 앱 간에 독립적으로 관리됩니다.
메시지
메시지 API 엔드포인트가 반환하는 세션 대화 기록의 단일 항목입니다. 각 메시지에는 type(user 또는 agent)과 name을 포함하는 구조화된 from 객체와, 메시지 자체의 type이 포함됩니다:
external- 채팅 콘텐츠로 표시되도록 의도된 대화 메시지입니다.internal- 실행 중 도구 호출이나 검색과 같은 에이전트 작업 단계를 나타내는 선택적 메시지입니다.
실행
메시지를 보낼 때 생성되는 단일 에이전트 실행입니다. 실행에는 run_id가 있으며, 활성 상태 동안 이벤트를 스트리밍할 수 있고, 하나 이상의 완료된 메시지를 생성할 수 있습니다. 각 세션은 한 번에 하나의 활성 실행만 가질 수 있습니다.
최종 사용자
user 필드는 세션을 귀하의 애플리케이션 내 최종 사용자 범위로 지정합니다. 내부 사용자 ID나 UUID와 같은 안정적이고 불투명한 ID를 사용하세요. 애플리케이션에서 필요하지 않은 경우 이메일이나 기타 개인식별정보(PII)는 피하세요. 동일한 user 값으로 생성된 세션은 함께 그룹화되어 사용자별 세션 목록 조회가 가능해집니다.
user가 생략되면 세션은 귀하의 개발자 계정 범위로 지정되며, 이후 최종 사용자별로 필터링할 수 없습니다. 프로덕션에서는 user를 전달하세요.
기존 세션에 대한 요청(경로에 {session_id}가 포함된 모든 엔드포인트)의 경우 user는 선택적인 소유권 확인 용도로 사용됩니다. 값을 제공하는 경우, 세션 생성 시 사용된 user 값과 일치해야 합니다. 그렇지 않으면 API는 404 session_not_owned를 반환합니다. GET 및 DELETE 요청에서는 쿼리 파라미터로, POST 및 PATCH 요청에서는 JSON 본문에 담아 전달하세요. POST 또는 PATCH에서 user를 쿼리 파라미터로 전달하면 400 bad_request가 반환됩니다.
인증
모든 요청은 Authorization 헤더에 Bearer 토큰을 포함하여 인증해야 합니다:
Authorization: Bearer jnv_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API 키는 개발자 대시보드에서 생성됩니다.
User-Agent는 선택 사항입니다. SDK는 진단 목적으로 이 값을 설정할 수 있지만, API에서 필수로 요구하지는 않습니다.
키 형식: 키는 접두사 jnv_sk_로 시작하며 그 뒤에 base62로 인코딩된 무작위 문자열이 이어집니다.
제한: 개발자 계정당 최대 10개의 활성 API 키를 가질 수 있습니다.
API 엔드포인트
메시지 API
메시지 보내기는 주요 API 경로입니다. 첫 메시지에는 POST /messages를 사용하며, 이 요청은 하나의 요청으로 세션을 생성하고 실행을 시작합니다. 캡처된 session_id로 계속하는 경우에는 POST /sessions/{session_id}/messages를 사용합니다.
메시지 보내기
POST /messages
하나의 요청으로 영구 세션을 생성하고 첫 메시지를 보냅니다. 스트리밍 단발성 요청을 원한다면 ephemeral: true를 설정합니다. 이 경우 세션 ID가 반환되지 않고 이어서 계속할 수 없습니다. 데이터는 요청이 완료된 직후 삭제됩니다.
요청 본문
| 필드 | 유형 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
agent | string | 필수 | - | 에이전트의 슬러그 식별자 |
content | string | 조건부 | - | 메시지 텍스트. file_urls가 제공되지 않는 경우 필수 |
file_urls | string[] | 조건부 | - | 첨부할 파일의 URL. content가 제공되지 않는 경우 필수 |
user | string | 선택 | - | 귀하의 외부 최종 사용자 식별자(최대 255자). 생략하면 귀하의 개발자 계정으로 기본 설정됩니다 |
session_name | string | 선택 | - | 새 세션의 표시 이름(최대 200자) |
ephemeral | boolean | 선택 | false | 스트리밍 전용 단발성 요청입니다. 세션 ID가 반환되지 않고, 이어서 계속할 수 없으며, 데이터는 요청이 완료된 직후 삭제됩니다 |
stream | boolean | 선택 | true | SSE 스트리밍의 경우 true, JSON의 경우 false. MCP 인가에는 스트리밍이 필요합니다 |
include_progress | boolean | 선택 | true | stream_progress 이벤트를 생략하려면 false로 설정합니다. 스트리밍 전용 |
model | string | 선택 | - | 이 요청에 한해 일회성으로 모델을 재지정합니다. claude-sonnet-5와 같은 안정적인 모델 ID를 사용하십시오. 세션의 기본 모델은 변경되지 않습니다 |
additional_context | object[] | 선택 | - | 이 요청에만 적용되는 이름 지정 컨텍스트입니다. 추가 컨텍스트 참조 |
예시 - 스트리밍(기본값)
curl -N -X POST https://api.jenova.ai/v1/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"agent": "my-support-agent",
"user": "user_12345",
"content": "Hello, I need help with my account"
}'
응답은 SSE 스트림입니다(이벤트 형식은 스트리밍 (SSE) 참조). 영구 요청에는 새로운 session_id가 포함되며, ephemeral: true 요청에는 session_id가 포함되지 않고 반드시 스트리밍을 사용해야 합니다.
예시 - JSON(비스트리밍)
curl -X POST https://api.jenova.ai/v1/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"agent": "my-support-agent",
"user": "user_12345",
"content": "Hello, I need help with my account",
"stream": false
}'
응답
스트리밍 응답은 스트리밍 (SSE)에 문서화된 SSE 이벤트를 발생시킵니다. 비스트리밍 응답은 세션 계속하기에 표시된 것처럼 요청에 대한 stop_reason과 usage를 포함한 메시지 객체를 반환합니다. stop_reason은 end_run이며, 에이전트가 메시지를 생성한 후 실행이 취소된 경우에는 user_cancelled입니다.
에이전트가 메시지를 생성하기 전에 실행이 취소되면 API는 status: "cancelled", session_id, run_id, stop_reason: "user_cancelled", usage와 함께 200 OK를 반환합니다.
비스트리밍 실행이 90초가 지나도 여전히 처리 중인 경우, API는 status: "processing", session_id, run_id, 사람이 읽을 수 있는 message와 함께 202 Accepted를 반환합니다. 실행은 응답이 반환되거나 클라이언트 연결이 끊긴 후에도 계속되므로, 세션의 메시지를 확인하거나 더 긴 워크플로에는 스트리밍을 사용하십시오.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | missing_required_field | agent는 필수입니다 |
| 400 | invalid_payload | 잘못된 형식의 JSON이거나 필드의 유형이 유효하지 않습니다 |
| 400 | bad_request | 유효하지 않은 ephemeral 모드 또는 additional_context이거나, user/session_name이 최대 길이를 초과했습니다 |
| 400 | content_or_uploaded_files_required | content와 file_urls 중 어느 것도 제공되지 않았습니다 |
| 400 | content_too_long | 메시지 내용이 32,000 토큰을 초과했습니다 |
| 400 | exceed_max_upload_files | 하나의 요청에 서로 다른 파일 URL이 10개를 초과하여 포함되었습니다 |
| 400 | unsupported_file_format | 파일 URL의 확장자가 지원되지 않습니다 |
| 400 | invalid_file_url | 파일 URL의 형식이 올바르지 않거나 HTTPS가 아닙니다 |
| 400 | invalid_model_selection | model이 유효한 모델 ID가 아니거나, 에이전트의 기본 모델을 사용할 수 없습니다 |
| 402 | insufficient_credits | 세션을 생성하거나 메시지를 보내기에 크레딧이 충분하지 않습니다 |
| 404 | agent_not_found | 에이전트가 존재하지 않거나 귀하의 계정에서 접근할 수 없습니다 |
세션 계속하기
POST /sessions/{session_id}/messages
기존 영속 세션에 메시지를 전송하고 에이전트의 응답을 받습니다. 응답은 기본적으로 SSE를 통해 스트리밍되며, JSON으로 받으려면 stream: false로 설정하세요.
요청 본문
| 필드 | 유형 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
content | string | 조건부 | - | 메시지 텍스트. file_urls가 제공되지 않는 경우 필수 |
file_urls | string[] | 조건부 | - | 첨부할 파일의 URL. content가 제공되지 않는 경우 필수 |
stream | boolean | 아니오 | true | SSE 스트리밍의 경우 true, JSON의 경우 false. MCP 인증에는 스트리밍이 필요함 |
include_progress | boolean | 아니오 | true | stream_progress 이벤트를 생략하려면 false로 설정합니다. 스트리밍 전용 |
model | string | 아니오 | - | 이 요청에 한해 일회성으로 모델을 재정의합니다. claude-sonnet-5와 같은 안정적인 모델 ID를 사용하세요. 세션의 기본 모델은 변경되지 않습니다 |
additional_context | object[] | 선택 | - | 이 요청에만 적용되는 이름 지정 컨텍스트입니다. 추가 컨텍스트 참조 |
예시 - 스트리밍(기본값)
curl -N -X POST https://api.jenova.ai/v1/sessions/ses_abc123/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"content": "How do I reset my password?"
}'
예시 - JSON(비스트리밍)
curl -X POST https://api.jenova.ai/v1/sessions/ses_abc123/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"content": "How do I reset my password?",
"stream": false
}'
응답 200 OK
{
"id": "msg_xyz789",
"session_id": "ses_abc123",
"sequence": 4,
"from": {
"type": "agent",
"name": "my-support-agent"
},
"type": "external",
"time": "2026-05-19T10:31:05Z",
"content": "To reset your password, go to Settings > Security > Change Password...",
"model": "claude-sonnet-5",
"files": [],
"stop_reason": "end_run",
"usage": {
"cost": "0.0015"
}
}
세션에 이미 활성 실행이 있거나 대기 중인 메시지가 있는 경우, API는 status: "queued", session_id, run_id, message_id와 함께 JSON 202 Accepted를 반환합니다. 사용자 메시지는 해당 활성 실행에 의해 처리됩니다. additional_context가 포함된 요청은 대신 409 busy를 반환합니다.
비스트리밍 응답은 에이전트가 메시지를 생성하기 전에 실행이 취소된 경우의 status: "cancelled" 응답을 포함하여 메시지 보내기와 동일한 규칙을 따릅니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 유효하지 않음 |
| 400 | bad_request | 유효하지 않은 additional_context |
| 400 | content_or_uploaded_files_required | content와 file_urls 중 어느 것도 제공되지 않음 |
| 400 | content_too_long | 메시지 콘텐츠가 32,000 토큰을 초과함 |
| 400 | exceed_max_upload_files | 단일 요청에 서로 다른 파일 URL이 10개를 초과하여 포함됨 |
| 400 | unsupported_file_format | 파일 URL에 지원되지 않는 파일 확장자가 사용됨 |
| 400 | invalid_file_url | 파일 URL 형식이 잘못되었거나 HTTPS가 아님 |
| 400 | invalid_model_selection | model이 유효한 모델 ID가 아니거나, 세션의 모델을 더 이상 사용할 수 없음 |
| 402 | insufficient_credits | 메시지를 전송하기에 크레딧이 부족함 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 지정된 user와 일치하지 않음 |
| 409 | busy | 다른 업데이트가 진행 중이어서 세션을 일시적으로 사용할 수 없거나, 세션에 활성 실행이나 대기 중인 메시지가 있는 동안 additional_context가 전송됨 |
| 429 | too_many_pending | 세션에 이미 대기 중인 메시지가 200개 있음 |
| 503 | service_unavailable | 서비스를 일시적으로 사용할 수 없음 |
멱등성
POST /messages, POST /sessions/{session_id}/messages, POST /invoke는 선택적으로 Idempotency-Key 헤더(최대 255자)를 허용합니다. 네트워크 재시도나 중복 제출로 인해 중복된 실행이 생성되지 않도록, 논리적인 사용자 전송마다 고유한 키를 사용하십시오. 키는 24시간 동안 보관됩니다.
curl -N -X POST https://api.jenova.ai/v1/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: send-user_12345-2026-05-19T10:30:00Z" \
-d '{
"agent": "my-support-agent",
"user": "user_12345",
"content": "Hello"
}'
비스트리밍: 재시도하면 Idempotent-Replayed: true 헤더와 함께 저장된 응답이 반환되며, 요청 처리가 시작된 후 반환된 오류도 포함됩니다. 저장된 202 Accepted 응답은 그대로 다시 반환되므로, 결과를 확인하려면 실행 상태 조회 또는 메시지 목록 조회를 사용하십시오. 유효성 검사 오류나 크레딧 오류처럼 처리가 시작되기 전에 거부된 요청은 저장되지 않으므로, 재시도하면 다시 평가됩니다.
스트리밍: 스트림은 재생되지 않습니다. POST /messages 및 POST /sessions/{session_id}/messages의 경우, 실행 중이거나 완료된 후에 재시도하면 원본 run_id와, 영속적인 요청의 경우 session_id가 포함된 멱등성 오류가 반환됩니다. 영속적인 요청의 경우 활성 실행을 확인하려면 실행 상태 조회를 사용하고, 저장된 결과를 가져오려면 메시지 목록 조회를 사용하십시오. 스트리밍된 POST /invoke 결과는 스트림이 닫힌 후에는 가져올 수 없습니다. POST /invoke 재시도는 run_id와 session_id 대신 원래 id를 반환합니다.
완료된 스트리밍 재시도 예시:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": {
"code": "idempotency_key_reused",
"message": "This Idempotency-Key has already completed. Streaming responses cannot be replayed; use the returned session_id and run_id to retrieve the result."
},
"idempotency": {
"status": "completed",
"session_id": "ses_abc123",
"run_id": "run_abc123"
}
}
멱등성 오류
| 상태 코드 | 코드 | 조건 |
|---|---|---|
| 400 | bad_request | Idempotency-Key가 최대 길이를 초과함 |
| 409 | idempotency_key_reused | 동일한 키가 다른 요청과 함께 사용됨 |
| 409 | idempotency_key_in_use | 원본 요청이 아직 실행 중임 |
| 409 | idempotency_key_reused | 원본 스트리밍 요청이 이미 완료되어 재생할 수 없음 |
메시지 목록 조회
GET /sessions/{session_id}/messages
세션 메시지의 페이지네이션된 목록을 반환합니다. 기본적으로 external 대화 메시지만 반환됩니다. 첫 번째 페이지에는 가장 최근 메시지가 포함되며, 각 페이지 내에서 메시지는 시간순(오래된 것부터)으로 정렬됩니다. sequence는 세션 내에서 메시지의 정렬 번호입니다.
쿼리 파라미터
| 파라미터 | 유형 | 기본값 | 최대값 | 설명 |
|---|---|---|---|---|
limit | integer | 20 | 100 | 페이지당 메시지 수 |
cursor | string | - | - | 페이지네이션 커서 |
include | string | external | - | 반환할 메시지 유형: external, internal 또는 all |
예시
curl "https://api.jenova.ai/v1/sessions/ses_abc123/messages?limit=50" \
-H "Authorization: Bearer jnv_sk_xxx"
응답 200 OK
{
"items": [
{
"id": "msg_002",
"session_id": "ses_abc123",
"sequence": 4,
"from": {
"type": "agent",
"name": "my-support-agent"
},
"type": "external",
"time": "2026-05-19T10:31:05Z",
"content": "To reset your password, go to Settings > Security...",
"model": "claude-sonnet-5",
"stop_reason": "end_run"
}
],
"next_cursor": "",
"has_more": false
}
메시지 객체
| 필드 | 유형 | 설명 |
|---|---|---|
id | string | 메시지 ID(msg_ 접두사) |
session_id | string | 상위 세션 ID |
sequence | integer | 세션 내 정렬 번호. 메시지가 삭제된 후 번호가 재사용될 수 있음 |
from | object | 발신자 객체로, type(user 또는 agent)과 name을 포함 |
type | string | 대화 메시지의 경우 external, 에이전트 작업 단계의 경우 internal |
time | string | ISO 8601 타임스탬프 |
content | string | 텍스트 콘텐츠. 외부(external) 메시지에 존재 |
model | string | 응답을 생성한 안정적인 모델 ID. 에이전트 메시지에만 존재 |
files | array | 메시지에 포함된 첨부 또는 생성된 파일. 아래 파일 객체 참고. 메시지에 파일이 없으면 메시지 목록 조회 및 메시지 조회 응답에서 생략됨 |
stop_reason | string | 콘텐츠가 있는 외부(external) 에이전트 메시지에 존재. 값은 end_run |
agent | string | 실행 중인 에이전트 슬러그(가능한 경우) |
agent_name | string | 실행 중인 에이전트 표시 이름(가능한 경우) |
progress_events | array | 내부 메시지에 대해 기록된 활동(가능한 경우). 각 항목은 stream_progress 이벤트와 동일한 필드를 가짐 |
파일 객체
| 필드 | 유형 | 설명 |
|---|---|---|
file_id | string | Jenova 파일 ID. 알 수 없는 경우 빈 값 |
name | string | 파일 이름 |
url | string | 파일 URL. 알 수 없는 경우 빈 값 |
format | string | 소문자 파일 형식(예: pdf, png, csv) |
size | integer | 파일 크기(바이트 단위). 알 수 없는 경우 0 |
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | bad_request | 잘못된 쿼리 파라미터 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 지정된 user와 일치하지 않음 |
메시지 조회
GET /sessions/{session_id}/messages/{message_id}
ID로 단일 메시지를 조회합니다.
쿼리 파라미터
| 파라미터 | 유형 | 기본값 | 설명 |
|---|---|---|---|
include | string | external | 반환될 수 있는 메시지 유형: external, internal 또는 all |
응답 200 OK
목록 응답과 동일한 구조의 단일 메시지 객체를 반환합니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | bad_request | 잘못된 쿼리 파라미터 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 지정된 user와 일치하지 않음 |
| 404 | not_found | 해당 세션에 메시지가 존재하지 않음 |
파일 첨부
file_urls 필드에 공개적으로 접근 가능한 HTTPS URL을 전달하십시오.
| 제한 | 값 |
|---|---|
| 메시지당 최대 파일 수 | 10 |
| 최대 파일 크기 | 파일당 20MB |
지원 형식
- 이미지: JPG, JPEG, PNG, WebP
- 문서: PDF, DOCX, XLSX, PPTX, TXT, CSV, RTF, MD, HTML, XML, JSON, LOG
- 코드: JS, TS, TSX, JSX, PY, Java, Go, C, CPP, H, HPP, CS, RB, PHP, RS, Swift, KT, Scala, SQL, CSS, YAML, YML
파일 URL은 요청이 수락될 때가 아니라 실행 중 에이전트가 파일을 읽을 때 가져옵니다. 가져올 수 없는 URL이나 20MB를 초과하는 파일은 읽히지 않지만, 요청 자체는 거부되지 않습니다.
메시지를 조회할 때 첨부된 파일은 메시지의 files 배열에 나타납니다.
추가 컨텍스트
최종 사용자의 계정 정보처럼 메시지 하나에만 적용되는 이름 지정 컨텍스트를 additional_context로 전달합니다. 메시지 기록에 저장되지 않습니다.
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 영문 소문자, 숫자, 밑줄로 구성되며 영문자로 시작해야 합니다(최대 64자). 밑줄과 복수형 차이를 무시하고 요청 내에서 고유해야 합니다 |
content | string | 예 | 컨텍스트 텍스트. 비어 있으면 안 됩니다(최대 12,000 토큰) |
| 제한 | 값 |
|---|---|
| 메시지당 최대 항목 수 | 4 |
| 항목당 최대 토큰 수 | 12,000 |
customer_profile이나 order_details처럼 설명적인 이름을 사용하세요.
name 또는 content가 없거나 문자열이 아닌 항목은 400 invalid_payload를 반환합니다. 그 밖의 잘못된 항목은 400 bad_request를 반환합니다.
curl -N -X POST https://api.jenova.ai/v1/sessions/ses_abc123/messages \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"content": "How do I reset my password?",
"additional_context": [
{
"name": "customer_profile",
"content": "Plan: Pro. Last login: 2026-05-18."
}
]
}'
세션 API
세션은 최종 사용자와 에이전트 간의 지속적인 대화입니다. 대부분의 통합에서는 POST /messages를 사용하여 암묵적으로 세션을 생성할 수 있습니다.
세션 생성
POST /sessions
특정 에이전트에 연결된 비어 있는 영구 세션을 생성합니다. 첫 번째 메시지 이전에 세션 ID가 필요한 경우 사용합니다. 그렇지 않은 경우에는 POST /messages를 사용하는 것이 좋습니다.
참고:
POST /sessions에서는ephemeral을 사용할 수 없습니다. 단발성 요청에는ephemeral: true와 함께POST /messages를 사용하세요.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
agent | string | 예 | 에이전트의 slug 식별자 |
user | string | 아니오 | 귀하의 외부 최종 사용자 식별자(최대 255자). 생략하면 귀하의 개발자 계정으로 기본 설정됩니다 |
session_name | string | 아니오 | 세션의 표시 이름(최대 200자) |
예시
curl -X POST https://api.jenova.ai/v1/sessions \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"agent": "my-support-agent",
"user": "user_12345",
"session_name": "Billing inquiry"
}'
응답 201 Created
{
"id": "ses_abc123",
"session_name": "Billing inquiry",
"agent": "my-support-agent",
"user": "user_12345",
"model": "claude-sonnet-5",
"created_at": "2026-05-19T10:30:00Z",
"updated_at": "2026-05-19T10:30:00Z"
}
세션 객체
| 필드 | 유형 | 설명 |
|---|---|---|
id | string | 세션 ID(ses_ 접두사) |
session_name | string | 표시 이름 |
agent | string | 에이전트 slug |
agent_details | object | display_name을 포함한 에이전트 세부 정보. include=agent로 요청한 경우에만 포함됨 |
user | string | 최종 사용자 식별자. user 없이 생성된 세션의 경우 null |
model | string | 메시지에서 모델을 지정하지 않을 때 사용되는 모델. 세션 생성 시 에이전트의 기본 모델로 설정됨. 에이전트가 Jenova에 모델 선택을 맡기는 경우 비어 있음 |
created_at | string | ISO 8601 타임스탬프 |
updated_at | string | ISO 8601 타임스탬프 |
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | missing_required_field | agent는 필수입니다 |
| 400 | bad_request | ephemeral이 전달되었거나, user/session_name이 최대 길이를 초과함 |
| 402 | insufficient_credits | 세션을 생성할 크레딧이 부족함 |
| 404 | agent_not_found | 에이전트가 존재하지 않거나 귀하의 계정에서 접근할 수 없음 |
세션 목록 조회
GET /sessions
귀하의 세션 목록을 최근 업데이트순으로 페이지네이션하여 반환합니다.
쿼리 파라미터
| 파라미터 | 유형 | 기본값 | 최대값 | 설명 |
|---|---|---|---|---|
limit | integer | 20 | 100 | 페이지당 항목 수 |
cursor | string | - | - | 페이지네이션 커서 |
user | string | - | - | 최종 사용자 식별자로 필터링(최대 255자) |
agent | string | - | - | 에이전트 slug로 필터링 |
include | string | - | - | 각 세션에 agent_details를 추가하려면 agent로 설정 |
예시
curl "https://api.jenova.ai/v1/sessions?user=user_12345&limit=10" \
-H "Authorization: Bearer jnv_sk_xxx"
응답 200 OK
{
"items": [
{
"id": "ses_abc123",
"session_name": "Billing inquiry",
"agent": "my-support-agent",
"user": "user_12345",
"model": "claude-sonnet-5",
"created_at": "2026-05-19T10:30:00Z",
"updated_at": "2026-05-19T11:15:00Z"
}
],
"next_cursor": "2026-05-19T11:15:00Z|ses_abc123",
"has_more": true
}
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | bad_request | 유효하지 않은 쿼리 파라미터 |
세션 조회
GET /sessions/{session_id}
ID로 단일 세션을 조회합니다.
쿼리 파라미터
| 파라미터 | 유형 | 설명 |
|---|---|---|
include | string | 세션에 agent_details를 추가하려면 agent로 설정 |
응답 200 OK
세션 객체를 반환합니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | bad_request | 잘못된 쿼리 파라미터 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 전달된 user와 일치하지 않음 |
세션 이름 변경
PATCH /sessions/{session_id}
세션의 표시 이름을 업데이트합니다.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
session_name | string | Yes | 새 표시 이름(최대 200자) |
응답 200 OK
업데이트된 세션 객체를 반환합니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | missing_required_field | session_name이 필요함 |
| 400 | bad_request | session_name이 최대 길이를 초과함 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 제공된 user와 일치하지 않음 |
| 409 | busy | 다른 업데이트가 진행 중이어서 세션을 일시적으로 사용할 수 없음 |
세션 삭제
DELETE /sessions/{session_id}
세션과 해당 세션의 모든 메시지를 영구적으로 삭제합니다. 세션에 활성 실행이 없어야 합니다.
응답 204 No Content
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 제공된 user와 일치하지 않음 |
| 409 | busy | 세션에 활성 실행이 있음 - 먼저 취소하십시오 |
작업
이 엔드포인트들은 영속 세션에 대한 복구 및 편집 제어 기능입니다. 대부분의 통합은 활성 실행 취소만 필요하며, 세션 상태를 의도적으로 변경하거나 복구하고자 할 때만 다른 작업을 사용하십시오. 모든 작업은 최종 사용자에서 설명된 선택적 user 소유권 보호 기능을 지원합니다.
활성 실행 취소
POST /sessions/{session_id}/cancel
활성 에이전트 실행을 취소합니다. 취소 이전에 이미 완료된 메시지는 삭제되지 않습니다.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
run_id | string | No | 선택적 오래된 실행(stale-run) 보호 기능입니다. 제공되었으나 활성 실행과 일치하지 않으면 API는 409 stale_run을 반환합니다 |
응답 204 No Content
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | cancel_not_allowed | 취소할 활성 실행이 없거나 취소가 허용되지 않음 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 제공된 user와 일치하지 않음 |
| 409 | stale_run | 제공된 run_id가 활성 실행과 일치하지 않음 |
활성 실행 되돌리기
POST /sessions/{session_id}/undo
활성 실행을 취소하고 중지될 때까지 대기한 후, 해당 실행이 이미 추가한 메시지를 제거합니다. 되돌리기가 실행된 이후에는 추가 출력이 저장되지 않습니다.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
run_id | string | No | 선택적 오래된 실행(stale-run) 보호 기능입니다. 제공되었으나 활성 실행과 일치하지 않으면 API는 409 stale_run을 반환합니다 |
응답 200 OK
{
"session_id": "ses_abc123",
"run_id": "run_abc123",
"deleted": ["msg_002", "msg_001"]
}
메시지가 완료되기 전에 실행이 취소된 경우, deleted는 빈 배열이 됩니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | cancel_not_allowed | 되돌릴 활성 실행이 없거나 취소가 허용되지 않음 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 제공된 user와 일치하지 않음 |
| 409 | stale_run | 제공된 run_id가 활성 실행과 일치하지 않음 |
| 409 | busy | 다른 업데이트가 진행 중이어서 세션을 일시적으로 사용할 수 없음 |
최근 메시지 삭제
POST /sessions/{session_id}/messages/delete
유휴 상태인 세션에서 internal 메시지를 포함하여 가장 최근 count개의 메시지를 삭제합니다. 이러한 메시지를 확인하려면 메시지 목록 조회에서 include=all을 사용하세요. 세션에 활성 실행이 없어야 합니다.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
count | integer | Yes | 끝에서부터 삭제할 최근 메시지 수 (0보다 커야 함). 100보다 큰 값은 100으로 처리됨 |
응답 200 OK
{
"deleted": ["msg_002", "msg_001"]
}
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | bad_request | count가 누락, 0 또는 음수인 경우, 또는 삭제할 메시지가 없는 경우 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속해 있거나 제공된 user와 일치하지 않음 |
| 409 | busy | 세션에 활성 실행이 있음 |
세션 포크
POST /sessions/{session_id}/fork
원본 세션을 특정 메시지까지 복사하여 새 세션을 생성합니다. 원본 세션에는 활성 실행이 없어야 합니다.
요청 본문 (선택 사항)
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
message_id | string | No | 포크 지점 메시지 ID. 생략하면 마지막 메시지에서 포크됩니다 |
응답 201 Created
세션 생성과 동일한 구조로 새로 생성된 세션 객체를 반환합니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | bad_request | message_id가 유효하지 않음 |
| 402 | insufficient_credits | 세션을 포크하기에 크레딧이 부족함 |
| 404 | not_found | 이 세션에 message_id가 존재하지 않음 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속해 있거나 제공된 user와 일치하지 않음 |
| 409 | busy | 원본 세션에 활성 실행이 있음 |
실행 상태 조회
GET /sessions/{session_id}/runs/{run_id}
활성 실행의 현재 상태를 반환합니다. SSE 연결이 끊어진 후 또는 run_id를 반환한 멱등성 응답 이후에 사용하십시오. 실행이 완료된 후에는 GET /sessions/{session_id}/messages로 결과를 조회하십시오.
응답 200 OK
{
"session_id": "ses_abc123",
"run_id": "run_abc123",
"status": "streaming",
"started_at": "2026-05-19T10:30:00Z",
"updated_at": "2026-05-19T10:30:06Z",
"content": "Partial visible response text so far"
}
status는 에이전트가 작업하는 동안 running이며, 응답 텍스트가 생성되기 시작하면 streaming, 실행이 끝난 직후 잠시 동안은 ended가 됩니다. 응답에는 stream_progress와 동일한 형식으로 최근 활동을 담은 progress_events가 포함될 수도 있습니다. status가 ended이거나 요청이 404 not_found를 반환하면 세션의 메시지를 가져오세요.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속해 있거나 제공된 user와 일치하지 않음 |
| 404 | not_found | 이 세션에 대해 실행이 활성 상태가 아님 |
크레딧
잔액 조회
GET /credits/balance
귀하의 현재 크레딧 잔액을 반환합니다.
응답 200 OK
{
"balance": "123.45"
}
에이전트 API
대시보드에서 커스텀 에이전트를 생성하고 편집하십시오. 에이전트 생성 및 편집을 위한 API 지원은 곧 제공될 예정입니다.
예약/백그라운드 워크플로는 현재 API를 통해 지원되지 않습니다. 지원은 곧 제공될 예정입니다.
에이전트 목록 조회
GET /agents
귀하의 계정에서 사용할 수 있는 에이전트를 반환합니다. 세션을 생성하거나 메시지를 보낼 때 agent 값을 사용하세요.
응답 200 OK
{
"agents": [
{
"agent": "jenova",
"display_name": "Jenova",
"description": "General-purpose Jenova agent"
},
{
"agent": "my-support-agent",
"display_name": "Support Agent",
"description": "Answers customer questions"
}
]
}
| 필드 | 유형 | 설명 |
|---|---|---|
agent | string | agent 값으로 전달할 안정적인 에이전트 슬러그 |
display_name | string | 사람이 읽기 쉬운 표시 이름 |
description | string | 에이전트 설명 |
모델
모델 목록 조회
GET /models
메시지를 보내거나 POST /invoke를 호출할 때 model 필드에서 사용할 수 있는 모든 모델을 반환합니다.
응답 200 OK
{
"models": [
{
"id": "claude-opus-4-8",
"name": "Claude Opus 4.8",
"thinking_variant": "claude-opus-4-8-thinking"
},
{
"id": "claude-opus-4-8-thinking",
"name": "Claude Opus 4.8 (Thinking)"
},
{
"id": "claude-sonnet-5",
"name": "Claude Sonnet 5",
"thinking_variant": "claude-sonnet-5-thinking"
}
]
}
| 필드 | 유형 | 설명 |
|---|---|---|
id | string | 안정적인 모델 식별자. 메시지 보내기 또는 모델 호출에서 model 값으로 전달하세요 |
name | string | 사람이 읽기 쉬운 표시 이름 |
thinking_variant | string | 사고/추론 변형의 모델 ID. 추론을 지원하는 기본 모델에만 존재함 |
thinking_variant가 있는 모델은 확장 추론을 지원합니다. 이를 활성화하려면 model 필드에 변형 ID를 직접 사용하세요.
메시지를 보낼 때 model을 지정하지 않으면 세션의 model이 사용됩니다. 이 값은 세션 생성 시 에이전트의 기본 모델로 설정됩니다.
모델 호출
POST /invoke
에이전트, 세션, 도구 없이 프롬프트를 모델에 직접 보냅니다. 응답은 기본적으로 SSE를 통해 스트리밍되며, JSON으로 받으려면 stream: false로 설정하세요.
요청 본문
| 필드 | 유형 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
model | string | 필수 | - | 모델 목록 조회의 모델 ID |
content | string | 필수 | - | 지침을 포함한 프롬프트 |
stream | boolean | 선택 | true | SSE 스트리밍의 경우 true, JSON의 경우 false |
user | string | 선택 | - | 귀하의 외부 최종 사용자 식별자(최대 255자). 생략하면 귀하의 개발자 계정으로 기본 설정됩니다 |
예시
curl -X POST https://api.jenova.ai/v1/invoke \
-H "Authorization: Bearer jnv_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"content": "Describe a forest in one sentence.",
"stream": false
}'
응답 200 OK
{
"id": "inv_abc123",
"model": "claude-sonnet-5",
"content": "Sunlight filters through tall pines onto a quiet, mossy floor.",
"usage": {
"cost": "0.0004"
}
}
스트리밍 응답은 stream_started를 보낸 다음, 모델이 텍스트를 생성하는 동안 stream_delta 이벤트를 보내고, usage가 포함된 stream_ended로 끝납니다. seq 순서대로 chunk_content 값을 연결하여 스트리밍된 응답을 구성하십시오. 요청이 실패하면 stream_ended 전에 stream_error가 전송됩니다. 이벤트에는 session_id와 run_id 대신 id가 포함됩니다.
비용을 확인할 수 없는 경우 usage.cost는 null입니다. 모델 호출이 시작된 후 비스트리밍 요청이 실패하면 오류 응답에 최상위 id 및 usage 필드가 포함됩니다.
스트리밍 요청은 최대 120분으로 제한됩니다. 비스트리밍 요청은 202 Accepted를 반환하는 대신 결과를 최대 30분까지 기다리며, 그때까지 결과가 준비되지 않으면 오류를 반환합니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | 잘못된 형식의 JSON이거나 필드의 유형이 유효하지 않습니다 |
| 400 | missing_required_field | content는 필수입니다 |
| 400 | content_too_long | 콘텐츠가 32,000 토큰을 초과했습니다 |
| 400 | bad_request | user가 최대 길이를 초과했습니다 |
| 400 | invalid_model_selection | model이 없거나 유효한 모델 ID가 아닙니다 |
| 400 | content_policy_violation | 모델 제공업체가 콘텐츠 정책 위반을 이유로 요청을 거부함 |
| 400 | llm_context_limit_reached | 입력이 모델의 컨텍스트 창을 초과함 |
| 402 | insufficient_credits | 모델을 호출하기에 크레딧이 충분하지 않습니다 |
| 500 | internal_error | 예기치 않은 서버 오류 |
| 502 | llm_api_error | 모델 제공업체 또는 상위 모델 API 오류 |
| 502 | llm_empty_response | 모델이 빈 응답을 반환함 |
| 502 | llm_reasoning_limit_reached | 모델이 응답 없이 추론 한도에 도달함 |
| 502 | llm_generation_limit_reached | 모델이 응답 없이 생성 한도에 도달함 |
| 503 | service_unavailable | 서비스를 일시적으로 사용할 수 없음 |
문서
GET /docs?lang=en
GET /doc?lang=en
이 참조 문서를 Markdown 형식으로 반환합니다. 언어를 선택하려면 lang을 사용하세요.
스트리밍 (SSE)
stream이 생략되거나 true(기본값)인 경우, 메시지 응답은 Server-Sent Events로 전달됩니다. 가져오거나 렌더링할 준비가 된 메시지를 식별하려면 message_completed 이벤트를 사용하세요.
타임아웃: SSE 연결은 실행이 끝날 때까지 유지됩니다. 실행 시간은 최대 120분으로 제한됩니다. 비스트리밍 메시지 요청은 최대 90초까지 대기한 후, 실행이 계속되는 동안 202 Accepted를 반환합니다. 비스트리밍 POST /invoke에 대해서는 모델 호출을 참조하십시오.
연결 헤더
메시지 스트림은 다음 헤더를 설정합니다:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
X-Run-Id: run_abc123
X-Run-Id는 첫 SSE 이벤트 이전에 사용할 수 있습니다. POST /invoke 스트림은 X-Run-Id를 설정하지 않으므로 stream_started의 id를 사용하세요.
재연결 및 복구
SSE 스트림은 재생되지 않습니다. 지속 요청에서 연결이 끊어진 경우, 캡처해 둔 session_id와 run_id를 사용하여 상태를 복구하세요:
curl "https://api.jenova.ai/v1/sessions/ses_abc123/runs/run_abc123" \
-H "Authorization: Bearer jnv_sk_xxx"
실행이 아직 활성 상태라면, 현재 상태, 부분 텍스트, 최근 진행 상황이 반환됩니다. status: "ended" 또는 404 not_found가 반환되면 해당 실행은 더 이상 활성 상태가 아니므로, 세션의 메시지를 가져와 완료된 출력을 대조하세요:
curl "https://api.jenova.ai/v1/sessions/ses_abc123/messages?limit=20" \
-H "Authorization: Bearer jnv_sk_xxx"
프레임 형식
각 SSE 프레임은 다음과 같은 표준 형식을 따릅니다:
event: <event_type>
data: <json_payload>
두 개의 줄바꿈이 각 프레임을 종료합니다.
이벤트 유형
스트림에는 수명 주기, 텍스트 델타, 사고, 진행 상황, 경고, 메시지 완료, MCP 연결, 오류, 최종 및 ping 이벤트가 포함됩니다. 일부 이벤트 유형은 관련이 있을 때만 전송됩니다.
일시적(ephemeral) 요청(ephemeral: true)의 경우, 모든 SSE 이벤트에서 session_id가 생략됩니다. 해당 단일 스트림 내에서 이벤트를 연관시키려면 run_id만 사용하십시오.
영구(persistent) 요청에 대한 최종 조정을 위해서는 stream_ended를 기다린 다음 메시지 목록 조회를 호출하십시오.
실행 범위 이벤트에 공통되는 필드:
| 필드 | 설명 |
|---|---|
session_id | 세션 ID. 일시적 스트림에서는 생략됩니다. 영구적인 POST /messages를 사용할 때 후속 요청을 위해 stream_started에서 이 값을 캡처하십시오 |
run_id | 사용 가능한 경우 현재 실행 ID |
id | invoke 요청 ID(inv_ 접두사 포함). session_id나 run_id가 없는 POST /invoke 스트림에만 존재 |
stream_started
실행이 시작될 때 한 번 전송됩니다.
| 필드 | 설명 |
|---|---|
agent | 사용 가능한 경우 세션 에이전트 슬러그 |
stream_delta
에이전트가 표시되는 응답 텍스트를 생성하는 동안 반복적으로 전송됩니다. seq 순서대로 chunk_content 값을 연결하여 스트리밍된 응답을 구성하십시오.
event: stream_delta
data: {"session_id":"ses_abc123","run_id":"run_abc123","chunk_content":"To reset your ","seq":1}
| 필드 | 설명 |
|---|---|
chunk_content | 텍스트 청크 |
seq | 스트림 내 단조 증가하는 청크 시퀀스 |
stream_thinking
에이전트가 사고(thinking) 출력을 내보내는 동안 반복적으로 전송됩니다. 별도의 사고 표시기나 추적 뷰에 사용하십시오. 최종 응답 텍스트에 연결하지 마십시오.
| 필드 | 설명 |
|---|---|
content | 사고 텍스트 청크 |
stream_progress
문서 읽기, 웹 검색 또는 사용자 작업 대기와 같이 생성 중 사용자에게 표시되는 활동을 보고합니다. 이러한 이벤트는 임시 UI 표시용입니다. 알 수 없는 필드는 무시하세요. 권위 있는 메시지 기록에는 완료된 메시지를 사용하세요.
메시지 요청에 include_progress: false를 설정하면 stream_progress만 생략됩니다. 라이프사이클 이벤트, ping, message_completed, 오류 및 종료 이벤트는 관련이 있을 경우 여전히 전송됩니다.
| 필드 | 설명 |
|---|---|
state | 활동 상태: running, success, failed 또는 skipped. 알 수 없는 값도 정상적으로 처리하십시오 |
label | 사람이 읽을 수 있는 활동 레이블 |
일부 진행 상황 이벤트에는 선택적 표시 힌트로 url, file_name, 또는 server_name이 포함될 수 있습니다.
message_completed
메시지가 완료되어 가져오거나 렌더링할 준비가 될 때마다 전송됩니다.
이것은 경계 마커일 뿐, 전체 메시지 객체가 아닙니다. 콘텐츠나 메타데이터가 필요한 경우 메시지를 가져오십시오.
event: message_completed
data: {"session_id":"ses_abc123","run_id":"run_abc123","message_id":"msg_abc123","sequence":4,"from":{"type":"agent","name":"my-support-agent"},"type":"external"}
| 필드 | 설명 |
|---|---|
message_id | 완료된 메시지 ID |
sequence | 세션 내 순서 번호 |
from | type(user 또는 agent)과 name을 포함하는 발신자 객체 |
type | 메시지 유형: external 또는 internal |
mcp_connection
에이전트가 계속하기 전에 최종 사용자가 하나 이상의 MCP 서버를 연결하거나 승인해야 할 때 전송됩니다. 이 이벤트는 스트리밍 모드에서만 사용할 수 있습니다.
| 필드 | 설명 |
|---|---|
connection_server_list | 연결 작업이 필요한 MCP 서버. 각 서버에는 mcp_server_id, mcp_server_name, 선택 사항인 auth_url이 포함됩니다 |
user_action_deadline_unix | 연결 사용자 작업이 만료되는 Unix 타임스탬프 |
mcp_connection_resolved
MCP 연결 사용자 작업이 해결되었거나 만료되었을 때 전송됩니다.
공통 실행 범위 필드 외에 추가 필드는 없습니다.
warning
실행 중 치명적이지 않은 경고에 대해 전송됩니다.
| 필드 | 설명 |
|---|---|
message | 사람이 읽을 수 있는 치명적이지 않은 경고 |
code | 선택적 경고 코드 |
stream_error
실행이 실패했을 때 전송됩니다. 이어서 success: false 및 stop_reason: "error"가 포함된 최종 stream_ended 이벤트가 뒤따를 수 있습니다.
| 필드 | 설명 |
|---|---|
code | 오류 코드 |
message | 사람이 읽을 수 있는 오류 메시지 |
stream_ended
실행이 종료되면 한 번 전송됩니다. 이는 스트림의 마지막 이벤트입니다.
event: stream_ended
data: {"session_id":"ses_abc123","run_id":"run_abc123","success":true,"stop_reason":"end_run","usage":{"cost":"0.0032"}}
취소된 실행 예시:
event: stream_ended
data: {"session_id":"ses_abc123","run_id":"run_abc123","success":false,"stop_reason":"user_cancelled","usage":{"cost":"0.0012"}}
| 필드 | 설명 |
|---|---|
success | 실행이 성공적으로 완료되었는지 여부 |
stop_reason | 실행 종료 이유: end_run, user_cancelled, user_action_timeout, 또는 error |
usage | 이 요청에 대한 사용량 객체. cost는 항상 포함되며, 비용을 확인할 수 없는 경우 null입니다 |
ping
프록시/CDN 타임아웃을 방지하기 위해 15초마다 전송되는 킵얼라이브 프레임입니다. 클라이언트에서는 무시하십시오.
MCP 서버 통합
**Model Context Protocol (MCP)**을 통해 귀하의 에이전트를 외부 도구에 연결하십시오:
- Jenova 관리형 MCP 서버: 검색, 콘텐츠 검색, 문서 생성 및 기타 기본 제공 기능을 위해 Jenova가 호스팅하는 서버
- 원격 MCP 서버: 귀하의 에이전트를 위해 구성된 기타 원격 MCP 서버
MCP 서버는 에이전트를 생성하거나 편집할 때 대시보드에서 구성해야 합니다. 자체 MCP 서버를 사용하려면 이를 커스텀 에이전트에 추가한 다음 API를 통해 해당 에이전트를 호출하십시오. API는 에이전트 구성에서 활성화된 도구를 실행하며, API 요청에서 추가 설정이 필요하지 않습니다.
에이전트가 응답 중 MCP 도구를 사용할 때, 진행 이벤트는 발생하는 대로 스트림으로 전송됩니다:
event: stream_progress
data: {"session_id":"ses_...","run_id":"run_...","state":"running","label":"Searching Google"}
실행 중 에이전트가 최종 사용자에게 MCP 서버 연결 또는 승인을 요구하는 경우, 스트리밍 응답에 mcp_connection 및 mcp_connection_resolved 이벤트가 포함될 수 있습니다. 최종 사용자에게 연결 서버 목록을 표시하고, 제공된 auth_url이 있으면 여세요. 최종 사용자가 서버를 연결하거나 승인하는 동안 SSE 스트림을 열어 두세요.
승인이 완료되면 Jenova가 토큰을 저장하고, 승인 창에는 완료 페이지가 표시되며, 동일한 실행이 자동으로 계속됩니다. 최종 사용자는 메시지를 다시 보낼 필요가 없습니다.
최종 사용자가 user_action_deadline_unix 전에 연결, 승인 또는 건너뛰기나 음소거를 하지 않으면 실행은 stop_reason: "user_action_timeout"으로 종료됩니다. POST /sessions/{session_id}/cancel로 활성 실행을 취소할 수도 있습니다.
auth_url을 클라이언트 측에 저장하세요. 승인 중 클라이언트 연결이 끊어져도 이 URL은 user_action_deadline_unix까지 유효합니다. 지속 요청의 경우 실행 상태 조회로 실행을 확인하거나 실행이 끝난 후 메시지를 가져오세요.
비스트리밍 요청(stream: false)은 MCP 연결 사용자 작업을 지원하지 않습니다. 이 상호작용이 필요할 수 있는 에이전트에는 스트리밍을 사용하세요.
MCP 연결 건너뛰기
POST /sessions/{session_id}/mcp/connection/skip
대기 중인 MCP 연결 사용자 작업을 무시하고 해당 연결 없이 실행을 계속하도록 합니다.
동일한 최종 사용자와 에이전트에 대해 한 서버의 향후 연결 프롬프트를 음소거하려면 mcp_server_id와 mute를 포함하세요. mute에는 30m, 24h, 7d와 같은 기간 또는 forever를 지정할 수 있습니다.
요청 본문
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
run_id | string | 예 | mcp_connection 이벤트의 활성 실행 ID |
mcp_server_id | string | 아니요 | mute 사용 시 필수입니다. 이벤트의 mcp_server_id를 사용하세요 |
mute | string | 아니요 | 30m, 24h, 7d와 같은 기간 또는 forever |
응답 204 No Content
스트림은 mcp_connection_resolved를 내보낸 다음, 실행은 동일한 run_id로 계속됩니다.
오류
| 상태 | 코드 | 조건 |
|---|---|---|
| 400 | invalid_payload | JSON 형식이 잘못되었거나 필드 유형이 올바르지 않음 |
| 400 | bad_request | run_id가 없거나, 활성 실행이 없거나, 건너뛸 MCP 연결이 없음 |
| 400 | bad_request | 잘못된 mute, mute가 설정되었지만 mcp_server_id가 없음, 또는 mcp_server_id가 이 세션에 유효하지 않음 |
| 404 | session_not_found | 세션이 존재하지 않음 |
| 404 | session_not_owned | 세션이 다른 개발자에게 속하거나 지정된 user와 일치하지 않음 |
| 409 | stale_run | run_id가 활성 실행과 일치하지 않음 |
결제
모든 비용은 귀하의 개발자 크레딧 잔액에서 차감됩니다. www.jenova.ai/platform에서 사용량을 확인하고 크레딧을 충전할 수 있습니다.
가격
| 작업 | 비용 |
|---|---|
| 세션 생성 | POST /sessions 또는 POST /messages로 생성되는 지속 세션마다 $0.01 고정 요금 |
| 세션 포크 | $0.05 고정(별도의 세션 생성 요금 없음) |
| 메시지 전송 | 가변 (아래 참조) |
| 모델 호출 | 가변 (모델 및 토큰 기준) |
메시지 비용은 다음에 따라 결정됩니다:
- 모델 - 모델마다 토큰당 비용이 다릅니다
- 컨텍스트 길이 - 세션이 길어질수록 요청당 더 많은 입력 토큰을 소비합니다
- 워크플로 복잡도 - 워크플로가 길어지고 도구 사용(웹 검색, 파일 생성, 문서 분석)이 늘어나면 전체 토큰 소비량이 증가합니다
실제 비용은 스트리밍 요청의 경우 stream_ended.usage.cost로, 비스트리밍 JSON 요청의 경우 usage.cost로 반환됩니다.
크레딧 보류
각 POST /messages, POST /sessions/{session_id}/messages, POST /invoke 요청은 실행이 시작되기 전에 귀하의 크레딧 잔액에 $0.50 보류를 설정합니다. 이는 요청을 위한 자금을 예약하는 것입니다. 활성 실행에 대기열로 추가된 메시지(status: "queued"와 함께 202 Accepted)는 추가 보류를 생성하지 않으며, 활성 실행의 사용량은 귀하의 남은 잔액과 대조하여 확인됩니다.
요청이 완료되면 보류는 실제 비용으로 정산되며 차액은 해제됩니다. 실제 비용이 보류 금액을 초과하면 차액도 청구되므로 잔액이 0 미만으로 내려갈 수 있습니다. 취소되거나 실패한 요청은 이미 발생한 사용량에 대해서만 청구됩니다. 요청이 모델에 도달하기 전에 실패하면 전체 보류가 해제됩니다.
보류로 인해 진행 중인 요청 동안 귀하의 사용 가능한 잔액이 일시적으로 낮게 표시될 수 있습니다. POST /sessions/{session_id}/messages, 임시 POST /messages 또는 POST /invoke 요청에는 최소 $0.50의 사용 가능한 잔액이 필요합니다. 지속 세션 POST /messages 요청은 세션도 생성하므로, 보류 금액과 세션 생성 요금을 충당하기 위해 최소 $0.51이 필요합니다.
속도 제한
모든 개발자 계정은 세 가지 속도 제한 차원의 적용을 받습니다:
| 차원 | 기본값 | 설명 |
|---|---|---|
| RPM (분당 요청 수) | 200 | 60초 고정 윈도우 |
| RPD (일일 요청 수) | 10,000 | 24시간 고정 윈도우 |
| 동시 실행 | 10 | 동시에 진행 중인 요청 및 활성 실행의 최대 수 |
실행은 202 Accepted 응답이 반환되거나 클라이언트 연결이 끊긴 후에도 종료될 때까지 동시 슬롯을 유지합니다. POST /invoke 요청은 클라이언트 연결이 끊겨도 완료될 때까지 슬롯을 유지합니다.
GET 및 HEAD 요청은 동시 슬롯을 소비하지 않습니다. cancel, undo, mcp/connection/skip도 동시 슬롯을 소비하지 않으므로 모든 슬롯이 사용 중이어도 이러한 작업은 계속 사용할 수 있습니다. 이러한 요청은 여전히 RPM 및 RPD에 계산됩니다.
이와 별도로 모든 요청에 60초당 1,200건의 IP별 제한이 적용되며, 초과 시 동일한 429 rate_limit_exceeded 오류가 반환됩니다.
응답 헤더
인증된 API 응답에는 속도 제한 헤더가 포함됩니다:
| 헤더 | 설명 |
|---|---|
X-RateLimit-Limit | 귀하의 RPM 제한 |
X-RateLimit-Remaining | 현재 1분 윈도우 내 남은 요청 수 |
X-RateLimit-Reset | 현재 윈도우가 재설정되는 Unix 타임스탬프 |
Retry-After | 재시도 전 대기해야 하는 시간(초). 429 rate_limit_exceeded 및 503 write_freeze_active 응답에서 전송됨 |
일일 한도를 초과한 경우 X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset은 대신 일일 윈도우를 기준으로 표시됩니다.
제한을 초과하면 API는 429 Too Many Requests를 반환합니다:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please try again later."
}
}
오류 처리
즉시 발생하는 HTTP 오류와 스트리밍이 아닌 실행 오류는 일관된 형식을 따릅니다:
{
"error": {
"code": "error_code_string",
"message": "Human-readable description"
}
}
오류 메시지는 lang 또는 Accept-Language를 기준으로 현지화됩니다(현지화 참고).
스트리밍 실행 오류는 stream_error 이벤트로 전달됩니다. 실패한 실행이라도 success: false와 stop_reason이 설정된 최종 stream_ended 이벤트가 전송될 수 있습니다. 스트리밍이 아닌 실행 오류에는 최상위 usage 객체가 포함되며, 비용을 확인할 수 없는 경우 cost는 null입니다.
다음 오류는 모든 엔드포인트에서 발생할 수 있습니다:
| 상태 | 코드 | 조건 |
|---|---|---|
| 401 | invalid_api_key | API 키가 없거나, 유효하지 않거나, 폐기됨 |
| 402 | developer_not_activated | 개발자 계정이 아직 활성화되지 않음. 대시보드에서 크레딧을 구매하여 활성화하세요 |
| 403 | developer_disabled | 개발자 계정이 비활성화됨 |
| 403 | forbidden | 이 네트워크의 요청이 차단됨 |
| 413 | payload_too_large | 요청 본문이 1 MiB를 초과함 |
| 429 | rate_limit_exceeded | 속도 제한을 초과함. 속도 제한을 참조하세요 |
| 503 | write_freeze_active | 유지 관리로 인해 쓰기 요청이 일시적으로 비활성화됨 |
엔드포인트별 오류는 각 엔드포인트 하위에 인라인으로 문서화되어 있습니다.
시작 후 실행 오류
실행 오류는 메시지 요청이 수락된 후에 나타납니다. 스트리밍 모드에서는 stream_error 이벤트로 나타나며, 이후 success: false가 설정된 stream_ended가 이어질 수 있습니다. 스트리밍이 아닌 모드에서는 아래 HTTP 상태와 함께 JSON 오류 응답으로 반환됩니다.
| 스트리밍이 아닌 경우의 HTTP 상태 | 코드 | 조건 |
|---|---|---|
| 400 | content_policy_violation | 모델 제공업체가 콘텐츠 정책 위반을 이유로 요청을 거부함 |
| 400 | llm_context_limit_reached | 입력이 모델의 컨텍스트 창을 초과함 |
| 404 | session_not_found | 실행이 실행되기 전에 세션이 삭제됨 |
| 409 | busy | 실행이 시작되기 전에 세션이 사용 중 상태가 되거나 일시적으로 이용할 수 없게 됨 |
| 413 | total_image_size_exceeded | 결합된 이미지 페이로드가 모델의 요청당 크기 제한을 초과함 |
| 500 | internal_error | 예기치 않은 실행 실패 |
| 500 | response_interrupted | 실행이 중단됨. 메시지를 다시 보내세요 |
| 500 | response_interrupted_message_saved | 메시지가 저장된 후 실행이 중단됨. 다시 보내기 전에 세션의 메시지를 조회하세요 |
| 502 | llm_api_error | 모델 제공업체 또는 상위 모델 API 오류 |
| 502 | llm_empty_response | 모델이 빈 응답을 반환함 |
| 502 | llm_reasoning_limit_reached | 모델이 응답 없이 추론 한도에 도달함 |
| 502 | llm_generation_limit_reached | 모델이 응답 없이 생성 한도에 도달함 |
페이지네이션
세션 목록 조회와 메시지 목록 조회는 커서 기반 페이지네이션을 사용합니다:
{
"items": [],
"next_cursor": "2026-05-19T11:15:00Z|ses_abc123",
"has_more": true
}
| 파라미터 | 유형 | 기본값 | 최대값 | 설명 |
|---|---|---|---|---|
limit | integer | 20 | 100 | 페이지당 항목 수 |
cursor | string | - | - | 이전 next_cursor에서 얻은 불투명 커서 |
다음 페이지를 가져오려면 next_cursor 값을 URL 인코딩하여 cursor 쿼리 파라미터로 전달하십시오. has_more가 false이면 더 이상 결과가 없습니다. limit이 1-100 범위를 벗어나거나 커서가 유효하지 않으면 400 bad_request가 반환됩니다.
현지화
모든 엔드포인트는 오류 메시지 및 현지화된 콘텐츠의 언어를 제어하기 위해 선택적 lang 쿼리 파라미터를 허용합니다.
| 소스 | 우선순위 | 예시 |
|---|---|---|
lang 쿼리 파라미터 | 최고 | ?lang=zh |
Accept-Language 헤더 | 대체 | Accept-Language: ja |
| 기본값 | 최저 | English (en) |
모든 요청 URL에 ?lang=xx를 추가할 수 있습니다:
POST /sessions?lang=zh
GET /sessions/ses_abc123/messages?lang=ja
지원 언어: en, zh, ja, ko, es, fr, de, it, pt, ru, id, th, vi
개인정보 보호 및 데이터
Jenova는 Jenova 모델을 훈련시키기 위해 API 프롬프트, 출력, 대화 기록, 업로드된 파일, 에이전트 지시사항 또는 지식 베이스를 사용하지 않습니다.
Jenova는 제3자 모델 제공업체와 관련하여, 고객 콘텐츠가 제공업체 모델 훈련에 사용되지 않도록 하기 위해 상업용 API 채널, 계정 설정, 계약상 약속 또는 옵트아웃을 활용합니다.
Jenova는 미국 인프라를 사용하여 API 데이터를 저장하고 처리합니다. 제3자 제공업체는 개인정보 보호정책 및 이용약관에 설명된 대로 다른 관할권에서 데이터를 처리할 수 있습니다.
전체 내용은 이용약관, 개인정보 보호정책, 사용 정책을 참조하십시오.
지원
- 대시보드: www.jenova.ai/platform
- 이메일: [email protected]