REST API
서버에서 사용API 7개Nordy API
ComfyUI 워크플로를 실행하고 생성된 결과를 API로 가져옵니다.
- Base URL
- https://api.nordy.ai
- 인증 헤더API 키 발급
- api-key: $NORDY_API_KEY
이 페이지에서
시작하기
API 키 발급
API를 사용하려면 Pro 구독이 필요합니다. API 키 관리에서 키를 발급하세요. 사용 중인 키는 최대 3개까지 만들 수 있으며, 전체 키는 발급 직후 한 번만 표시됩니다.
발급받은 키를 api-key 헤더에 넣어 요청하세요. 키는 서버 환경 변수로 보관하고 브라우저 코드, 모바일 앱, 공개 저장소에 포함하지 마세요.
export NORDY_API_KEY="your_api_key"
export NORDY_BASE_URL="https://api.nordy.ai"Job 생성 한도
Job 생성에는 일일 한도가 있습니다.
빠른 시작
아래 예제는 Bash, curl, jq를 사용합니다. 환경 변수와 저장한 파일을 이어서 사용할 수 있도록 같은 터미널과 폴더에서 실행하세요.
1. 워크플로 준비. 필요한 결과를 저장할 Save 노드를 연결하고 Nordy ComfyUI에서 실행해 확인하세요. Export Workflow (API Format) 또는 Export (API) 결과를 prompt.json으로 저장합니다. 화면 편집용 JSON은 사용할 수 없습니다. 준비한 워크플로가 없다면 실행 예제를 사용하세요.
2. 작업 생성. 다음 명령을 한 번 실행하세요. 워크플로를 요청 본문으로 감싸고 생성 응답을 job.json에 저장합니다.
jq '{prompt: .}' prompt.json > request.json &&
curl --fail-with-body --silent --show-error --max-time 30 \
-X POST "$NORDY_BASE_URL/v1/api/job/comfy-prompt" \
-H "api-key: $NORDY_API_KEY" \
-H "content-type: application/json" \
--data-binary @request.json --output job.json &&
jq '{id, status}' job.json202 Accepted는 작업이 접수됐다는 뜻입니다. 반환된 id를 보관하고, 완료 여부는 다음 단계에서 확인하세요.
3. 결과 확인. 저장한 작업 ID로 현재 상태를 조회합니다.
JOB_ID=$(jq -er '.id' job.json) &&
curl --fail-with-body --silent --show-error --max-time 30 \
"$NORDY_BASE_URL/v1/api/job/$JOB_ID" \
-H "api-key: $NORDY_API_KEY" --output job-status.json &&
jq '{status, outputs, error}' job-status.json| 상태 | 다음 단계 |
|---|---|
queued / processing | 최소 5초 뒤 3단계만 다시 실행하세요. |
succeeded | outputs에 있는 파일을 내려받으세요. |
failed / canceled | error.code와 error.message를 확인하세요. 작업 실패를 참고할 수 있습니다. |
상태를 자동으로 확인하려면 자동 조회 스크립트를 사용하세요. 생성 요청이 시간 초과되면 다시 제출하기 전에 재시도와 시간 초과를 확인하세요.
4. 결과물 다운로드
작업이 성공한 뒤 다음 명령을 실행하면 첫 번째 결과를 output.bin으로 저장합니다. 파일 형식에 맞게 확장자를 바꾸고, 결과가 여러 개라면 각 URL에서 내려받으세요. 다운로드 URL에는 API 키를 보내지 마세요.
OUTPUT_URL=$(jq -er \
'select(.status == "succeeded") | .outputs[0].url // empty' job-status.json) &&
curl --fail --location --show-error \
--output output.bin --url "$OUTPUT_URL"결과물은 생성 시점부터 7일 뒤에 만료됩니다. 각 파일의
expiresAt전에 저장하세요. 결과물이 모두 만료되어도 작업은 조회할 수 있으며outputs: []로 반환됩니다.
실행 예제
예제를 골라 JSON을 prompt.json으로 저장한 뒤, 빠른 시작에 따라 작업을 생성하고 결과를 확인하세요.
| 목적 | 예제 |
|---|---|
| 텍스트로 이미지 생성 | DreamShaper |
| 체크포인트 없이 워크플로 실행 | 이미지 불러오기와 저장 |
DreamShaper로 이미지 생성
먼저 사용 가능한 체크포인트 이름을 확인하세요. 목록에 dreamshaper_8.safetensors가 없다면 4.inputs.ckpt_name을 사용 가능한 호환 체크포인트로 바꾸세요. 응답이 빈 객체라면 해당 노드를 사용할 수 없는 것입니다.
curl --fail-with-body --silent --show-error \
"$NORDY_BASE_URL/v1/api/comfy/object-info/CheckpointLoaderSimple" \
-H "api-key: $NORDY_API_KEY" --output object-info.json &&
jq -r '.CheckpointLoaderSimple.input.required.ckpt_name[0][]' object-info.json입력 이미지는 필요하지 않습니다.
전체 코드JSON
{
"3": {
"inputs": {
"seed": 102298450217384,
"steps": 20,
"cfg": 8,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": ["4", 0],
"positive": ["6", 0],
"negative": ["7", 0],
"latent_image": ["5", 0]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"4": {
"inputs": {
"ckpt_name": "dreamshaper_8.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Load Checkpoint"
}
},
"5": {
"inputs": {
"width": 256,
"height": 256,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Empty Latent Image"
}
},
"6": {
"inputs": {
"text": "beautiful scenery nature glass bottle landscape, purple galaxy bottle",
"clip": ["4", 1]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Positive)"
}
},
"7": {
"inputs": {
"text": "text, watermark",
"clip": ["4", 1]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Negative)"
}
},
"8": {
"inputs": {
"samples": ["3", 0],
"vae": ["4", 2]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"9": {
"inputs": {
"filename_prefix": "dreamshaper-api-example",
"images": ["8", 0]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
}
}| 변경할 내용 | 수정할 위치 |
|---|---|
| 긍정·부정 프롬프트 | 6.inputs.text, 7.inputs.text |
| 시드와 샘플링 설정 | 3.inputs |
| 이미지 크기와 생성 개수 | 5.inputs |
| 체크포인트 | 4.inputs.ckpt_name |
노드 간 연결값은 유지하세요. 목록에 있는 노드나 모델도 작업 실행 시 사용할 수 없는 경우가 있습니다.
URL의 이미지 불러오기와 저장
체크포인트나 커스텀 노드 없이 LoadImage → SaveImage로 이미지를 불러와 저장합니다. 이미지 URL을 자신의 파일 주소로 바꾸세요.
전체 코드JSON
{
"11": {
"inputs": {
"image": "https://your-public-host.example/input.png"
},
"class_type": "LoadImage",
"_meta": {
"title": "Load Image"
}
},
"12": {
"inputs": {
"filename_prefix": "nordy-api-example",
"images": [
"11",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
}
}로그인 쿠키나 별도 헤더 없이 접근할 수 있는 HTTPS URL을 사용하고, 연결값 ["11", 0]은 유지하세요. 서명된 URL은 작업이 끝날 때까지 유효해야 하며 HEAD와 GET 요청을 모두 허용해야 합니다. GET 전용 서명은 거부될 수 있습니다.
이미지를 해석한 뒤 다시 저장하므로 인코딩, 메타데이터, 투명도가 달라질 수 있습니다.
API 레퍼런스
API를 선택하면 파라미터, 응답 필드, 사용 예제를 확인할 수 있습니다. 각 상세 페이지의 ‘테스트하기’로 해당 API가 선택된 테스트 화면을 열 수 있습니다.
| 기능 | 메서드와 경로 | 성공 응답 |
|---|---|---|
| 작업 생성 | POST /v1/api/job/comfy-prompt | 202 |
| 작업 목록 조회 | GET /v1/api/job/list | 200 |
| 작업 상태와 결과 조회 | GET /v1/api/job/{id} | 200 |
| Job 취소 | POST /v1/api/job/cancel | 200 |
| Job 전체 취소 | POST /v1/api/job/cancel-all | 200 |
| 전체 노드 정의 조회 | GET /v1/api/comfy/object-info | 200 |
| 특정 노드 정의 조회 | GET /v1/api/comfy/object-info/{className} | 200 |
문제 해결
모든 HTTP 상태 코드, 오류 코드, Job 상태와 취소 결과는 응답과 오류에서 한눈에 확인할 수 있습니다.
요청 오류
Nordy 오류 응답에는 code, message, requestId가 포함됩니다. 고객 지원에 문의할 때 requestId를 함께 전달하세요.
전체 코드JSON
{
"statusCode": 400,
"code": "INVALID_INPUT",
"message": "The request is invalid.",
"requestId": "request-id",
"details": {
"field": "prompt"
}
}| 상태 코드와 오류 | 확인할 내용 |
|---|---|
400 INVALID_JSON / INVALID_INPUT | JSON 문법과 API 형식의 워크플로인지 확인하고, prompt로 한 번만 감싸세요. |
400 MULTIPLE_AUTH_CREDENTIALS | 로그인 쿠키를 제외하고 API 키만 보내세요. |
401 AUTHENTICATION_REQUIRED | api-key 헤더와 키 삭제 여부를 확인하세요. |
402 INSUFFICIENT_CREDIT | 크레딧 잔액을 확인하세요. |
403 PRO_SUBSCRIPTION_REQUIRED | Pro 구독이 활성화되어 있는지 확인하세요. |
403 USER_SUSPENDED | 계정 상태를 고객 지원에 문의하세요. |
404 JOB_NOT_FOUND | 작업 ID와 API 키의 계정을 확인하세요. 이 API로 생성한 작업만 조회할 수 있습니다. |
413 REQUEST_BODY_TOO_LARGE | 요청 JSON 크기를 50 MiB 이하로 줄이세요. |
415 UNSUPPORTED_MEDIA_TYPE | Content-Type: application/json으로 요청하세요. |
429 DAILY_JOB_LIMIT_EXCEEDED | 생성 한도가 초기화된 후 다시 시도하세요. |
5xx | 조회 요청은 잠시 후 다시 시도하세요. 생성 요청은 아래 재시도 안내를 따르세요. |
API별 응답은 API 레퍼런스에 정리되어 있습니다. 오류를 처리할 때는 알려진 코드뿐 아니라 새로 추가될 수 있는 코드도 보존하세요.
작업 실패
HTTP 200은 조회 요청이 성공했다는 뜻입니다. 작업의 실행 결과는 status와 error를 함께 확인하세요.
| 작업 오류 | 다음 단계 |
|---|---|
INVALID_INPUT | 노드 입력값과 모델 이름을 확인하세요. error.details.node_errors에 문제가 있는 노드가 표시될 수 있습니다. |
INSUFFICIENT_CREDIT | 새 작업을 만들기 전에 크레딧 잔액을 확인하세요. |
EXECUTION_TIMEOUT / WORKER_UNAVAILABLE / EXECUTION_FAILED | 오류 메시지를 확인하고, 문제가 계속되면 고객 지원에 문의하세요. |
JOB_CANCELED | 작업 상태가 canceled입니다. 다른 작업 오류는 failed 상태를 사용합니다. |
입력 오류의 상세 정보에는 제출한 값이나 모델 목록이 포함될 수 있습니다. 고객 지원에 필요한 부분만 전달하고 전체 오류 객체를 공개하지 마세요.
전체 코드JSON
{
"id": "68abcdef0123456789abcdef",
"user_metadata": {},
"status": "failed",
"createdAt": "2026-08-26T00:00:00.000Z",
"startedAt": "2026-08-26T00:00:02.000Z",
"completedAt": "2026-08-26T00:00:04.000Z",
"outputs": null,
"error": {
"code": "INVALID_INPUT",
"message": "The job input is invalid.",
"details": {
"error": {
"type": "prompt_outputs_failed_validation",
"message": "Prompt outputs failed validation"
},
"node_errors": {
"4": {
"class_type": "CheckpointLoaderSimple",
"errors": [
{
"type": "value_not_in_list",
"message": "Value not in list"
}
]
}
}
}
}
}재시도와 시간 초과
- 생성 요청이 시간 초과되거나 응답이 끊겼다고 바로 다시 제출하지 마세요. 이미 작업이 생성됐을 수 있습니다. 보관한 ID나 최근 작업 목록을 확인한 뒤 다시 제출할지 결정하세요.
- GET 조회는 잠시 기다린 뒤 같은 ID로 다시 요청할 수 있습니다. 대기·실행 중에는
Retry-After를 따르고, 인증·입력 오류는 원인을 해결한 뒤 재시도하세요.
요청 제한
프롬프트·메타데이터의 허용 형식, 크기, 노드 수는 입력 제한에서 확인하세요.
고급 사용
상태 자동 조회
빠른 시작의 환경과 job.json으로 아래 스크립트를 실행하세요. 유효한 Retry-After가 없으면 5초 간격으로 조회하며, 최신 응답을 job-status.json에 저장합니다.
스크립트는 2시간 뒤 조회를 중단하지만 작업을 취소하지는 않습니다. 성공하면 결과 URL을, 실패하면 오류를 출력합니다. 성공한 결과는 4단계로 내려받으세요.
전체 코드bash
if ! JOB_ID=$(jq -er '.id' job.json); then
printf 'Could not read the Job ID from job.json.\n' >&2
exit 1
fi
POLL_TIMEOUT_SECONDS=7200
POLL_DEADLINE=$((SECONDS + POLL_TIMEOUT_SECONDS))
while true; do
REMAINING_SECONDS=$((POLL_DEADLINE - SECONDS))
if (( REMAINING_SECONDS <= 0 )); then
printf 'Timed out waiting for Job %s.\n' "$JOB_ID" >&2
exit 1
fi
REQUEST_TIMEOUT_SECONDS=30
if (( REMAINING_SECONDS < REQUEST_TIMEOUT_SECONDS )); then
REQUEST_TIMEOUT_SECONDS=$REMAINING_SECONDS
fi
if ! HTTP_STATUS=$(curl --fail-with-body --silent --show-error \
--max-time "$REQUEST_TIMEOUT_SECONDS" \
"$NORDY_BASE_URL/v1/api/job/$JOB_ID" \
-H "api-key: $NORDY_API_KEY" \
--dump-header job-headers.txt \
--output job-status.json \
--write-out '%{http_code}'); then
if [ -s job-status.json ]; then cat job-status.json >&2; fi
exit 1
fi
case "$HTTP_STATUS" in
2??) ;;
*)
printf 'Unexpected HTTP status: %s\n' "$HTTP_STATUS" >&2
cat job-status.json >&2
exit 1
;;
esac
if (( SECONDS >= POLL_DEADLINE )); then
printf 'Timed out waiting for Job %s.\n' "$JOB_ID" >&2
exit 1
fi
if ! STATUS=$(jq -er '.status' job-status.json); then
printf 'The response did not include a valid Job status.\n' >&2
exit 1
fi
printf 'Job status: %s\n' "$STATUS"
case "$STATUS" in
succeeded|failed|canceled) break ;;
queued|processing) ;;
*)
printf 'Unknown Job status: %s\n' "$STATUS" >&2
exit 1
;;
esac
if (( SECONDS >= POLL_DEADLINE )); then
printf 'Timed out waiting for Job %s.\n' "$JOB_ID" >&2
exit 1
fi
RETRY_AFTER=$(
awk -F ': *' '
tolower($1) == "retry-after" {
gsub("\\r", "", $2)
print $2
exit
}
' job-headers.txt
)
case "$RETRY_AFTER" in
''|*[!0-9]*) RETRY_AFTER=5 ;;
esac
REMAINING_SECONDS=$((POLL_DEADLINE - SECONDS))
if (( RETRY_AFTER > REMAINING_SECONDS )); then
RETRY_AFTER=$REMAINING_SECONDS
fi
sleep "$RETRY_AFTER"
done
if [ "$STATUS" = "succeeded" ]; then
jq -r '.outputs[] | "\(.kind)\t\(.url)"' job-status.json
else
jq '{code: .error.code, message: .error.message}' job-status.json
exit 1
fi다음 페이지 조회
첫 페이지를 조회합니다.
curl --fail-with-body --silent --show-error --max-time 30 --get \
"$NORDY_BASE_URL/v1/api/job/list" \
-H "api-key: $NORDY_API_KEY" \
--data-urlencode 'limit=20' --output jobs.json &&
jq . jobs.json아래 명령은 반환된 next_cursor를 그대로 전달해 다음 페이지를 조회하고 jobs.json을 갱신합니다. 값이 null이면 요청하지 않습니다.
NEXT_CURSOR=$(jq -er '.next_cursor // empty' jobs.json) &&
curl --fail-with-body --silent --show-error --max-time 30 --get \
"$NORDY_BASE_URL/v1/api/job/list" \
-H "api-key: $NORDY_API_KEY" \
--data-urlencode 'limit=20' \
--data-urlencode "cursor=$NEXT_CURSOR" --output jobs.json &&
jq . jobs.json대기 작업 취소
실행 준비 전인 Pending(대기) 상태의 Job만 취소할 수 있습니다. Job ID 배열을 지정하려면 Job 취소, 계정의 대기 작업을 모두 취소하려면 Job 전체 취소를 사용하세요. 요청 예제와 응답 설명은 각 레퍼런스에서 확인할 수 있습니다.
사용자 데이터 연결
생성 요청의 user_metadata로 애플리케이션의 주문이나 기록을 작업에 연결할 수 있습니다. 예를 들어 다음 값을 사용하세요.
{"order_id": "example-order-001"}메타데이터는 Job 조회 시 함께 반환되며, 워크플로 입력이나 중복 생성 방지에 사용되지 않습니다. 허용되는 값은 입력 제한을 확인하세요.
용어
| 용어 | 의미 |
|---|---|
| 워크플로 | 콘텐츠를 생성하거나 처리하도록 연결한 ComfyUI 노드 모음입니다. |
| API 형식의 프롬프트 | 실행할 노드와 연결을 정의한 JSON입니다. |
| 노드 | 모델 불러오기, 이미지 저장 등 워크플로 안에서 한 단계를 수행합니다. |
| 작업(Job) / 작업 ID | 워크플로 실행 한 건과 이를 조회하는 ID입니다. |
outputs | 다운로드 URL과 만료 시각을 포함하는 결과물 목록입니다. 하나의 작업에서 여러 파일이 생성될 수 있습니다. |