# 작업 및 오류

작업을 조회하고 통합 문서를 다운로드하며 요청 실패 원인을 확인하세요.

공식 문서: https://img2excel.net/ko/docs/api/jobs

`GET /api/v1/jobs/{job_id}`

동기 엔드포인트는 완료된 변환 결과를 바로 반환합니다. 이 작업 엔드포인트는 비동기 처리, 멱등성 재시도로 반환된 진행 중 작업 조회, 결과 보관 기간 내 다운로드 URL 갱신에 사용합니다. 동기 변환 실패는 `422`와 작업 응답을 반환하지만 기존 작업 조회는 `200`을 반환하므로 항상 `status`를 확인하세요.

변환 작업의 현재 상태를 조회합니다. 이미지와 손글씨 변환이 같은 엔드포인트를 사용합니다.

## 요청

| 매개변수 | 위치 | 필수 | 설명 |
| --- | --- | --- | --- |
| `job_id` | 경로 | 예 | 작업 생성 시 반환된 `id`. |
| `Authorization` | 요청 헤더 | 예 | `Bearer $IMG2EXCEL_API_KEY`. 작업을 만든 계정의 키를 사용하세요. |

```bash
curl --fail-with-body https://img2excel.net/api/v1/jobs/job_0123456789abcdef0123456789abcdef \
  -H "Authorization: Bearer $IMG2EXCEL_API_KEY"
```

유효한 요청은 변환 자체가 실패했어도 **200 OK**를 반환합니다. JSON의 `status`를 확인하세요. HTTP 요청 성공이 파일 완성을 뜻하지는 않습니다.

## 작업 상태

| 상태 | 의미 | 다음 단계 |
| --- | --- | --- |
| `queued` | 업로드가 수락되었고 실행 대기 중입니다. | 2~3초 후 다시 조회하세요. |
| `processing` | 변환 중입니다. | 2~3초 후 다시 조회하세요. |
| `succeeded` | 통합 문서가 준비되었습니다. | `result.download_url`에서 다운로드하고 폴링을 중지하세요. |
| `failed` | 변환에 실패했습니다. | `error.code`와 `error.message`를 확인하고 폴링을 중지하세요. |
| `expired` | 결과 보관 기간이 끝났습니다. | 폴링을 중지하세요. 필요하면 새 멱등성 키로 새 작업을 만드세요. |

## 응답

### 변환 성공

```json
{
  "id": "job_0123456789abcdef0123456789abcdef",
  "type": "image-to-excel",
  "status": "succeeded",
  "credits_reserved": 1,
  "credits_used": 1,
  "created_at": "2026-09-07T12:00:00.000Z",
  "completed_at": "2026-09-07T12:00:18.000Z",
  "result": {
    "filename": "table_result.xlsx",
    "content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "size_bytes": 17330,
    "download_url": "https://signed-storage-url.example/...",
    "download_url_expires_in": 900
  }
}

```

위 URL은 예시입니다. 실제 작업이 반환한 URL을 사용하세요.

| 필드 | 타입 | 설명 |
| --- | --- | --- |
| `id` | 문자열 | 작업 ID. |
| `type` | 문자열 | `image-to-excel` 또는 `handwriting-to-excel`. |
| `status` | 문자열 | 위의 다섯 상태 중 하나. |
| `credits_reserved` | 정수 | 변환에 필요한 크레딧 수. |
| `credits_used` | 정수 | 변환에서 사용한 크레딧 수. |
| `created_at` | 문자열 | ISO 8601 형식의 UTC 시각. |
| `completed_at` | 문자열 또는 null | 완료 시각. 완료 전에는 `null`. |
| `result` | 객체 | 성공한 작업의 결과를 이용할 수 있을 때 포함됩니다. |
| `error` | 객체 | 변환 실패 시 포함되며 `code`와 `message`를 담습니다. |

### 결과 필드

| 필드 | 타입 | 설명 |
| --- | --- | --- |
| `filename` | 문자열 | 권장 통합 문서 파일명. |
| `content_type` | 문자열 | XLSX MIME 타입. |
| `size_bytes` | 정수 또는 null | 파일 크기(바이트). 알 수 없으면 `null`. |
| `download_url` | 문자열 | 서명된 임시 다운로드 URL. |
| `download_url_expires_in` | 정수 | URL 유효 시간(초): `900`(15분). |

결과는 완료 후 24시간 이용할 수 있습니다. 그 안에 URL이 만료되면 작업을 다시 조회해 새 URL을 받으세요. 서명된 다운로드 URL을 로그에 남기거나 공개하지 마세요.

### 변환 실패

변환 실패는 작업 응답에 다음과 같이 표시됩니다.

```json
{
  "id": "job_0123456789abcdef0123456789abcdef",
  "type": "image-to-excel",
  "status": "failed",
  "credits_reserved": 1,
  "credits_used": 0,
  "created_at": "2026-10-04T09:00:00.000Z",
  "completed_at": "2026-10-04T09:00:18.000Z",
  "error": {
    "code": "CONVERSION_FAILED",
    "message": "The conversion could not be completed."
  }
}
```

변환 실패 시 크레딧은 차감되지 않습니다. 재시도 전에 오류 메시지를 확인하세요. 새 변환에는 새 멱등성 키가 필요하며 이전 키는 같은 실패 작업을 반환합니다.

## 폴링 및 다운로드

`pip install requests`로 `requests`를 설치하고 `IMG2EXCEL_API_KEY`를 설정한 다음 `job_id`를 작업 ID로 바꾸세요. 최대 60회 조회합니다. 네트워크나 HTTP 오류가 발생하면 스크립트가 중지됩니다. 운영 환경에서는 아래 지침에 따라 일시적 오류를 처리하세요.

```python
import os
import time
import requests

job_id = "job_0123456789abcdef0123456789abcdef"
headers = {"Authorization": f"Bearer {os.environ['IMG2EXCEL_API_KEY']}"}

for _ in range(60):
    response = requests.get(
        f"https://img2excel.net/api/v1/jobs/{job_id}",
        headers=headers,
        timeout=30,
    )
    response.raise_for_status()
    job = response.json()

    if job["status"] == "succeeded":
        xlsx = requests.get(job["result"]["download_url"], timeout=60)
        xlsx.raise_for_status()
        with open(job["result"]["filename"], "wb") as output:
            output.write(xlsx.content)
        break
    if job["status"] in ("failed", "expired"):
        raise RuntimeError(job.get("error", {"code": job["status"]}))

    time.sleep(2)
else:
    raise TimeoutError("IMG2Excel conversion did not finish in time")

```

## 요청 오류

거부된 HTTP 요청은 2xx 이외의 상태와 오류 객체를 반환합니다.

```json
{
  "error": {
    "code": "INVALID_API_KEY",
    "message": "A valid API key is required."
  }
}
```

| HTTP 상태 | 코드 | 원인 | 해결 방법 |
| --- | --- | --- | --- |
| 400 | `INVALID_REQUEST` | 본문을 multipart 폼으로 읽을 수 없습니다. | HTTP 클라이언트의 multipart 업로드를 사용하세요. |
| 400 | `INVALID_FILE` | `file`이 없거나 파일이 아닙니다. | `file` 필드에 이미지를 첨부하세요. |
| 400 | `INVALID_IDEMPOTENCY_KEY` | 키가 200자를 초과합니다. | 헤더 값을 줄이세요. |
| 401 | `INVALID_API_KEY` | 키가 없거나 유효하지 않거나 만료·폐기되었거나 변환 권한이 없습니다. | Bearer 헤더와 [API 설정](https://img2excel.net/ko/settings/api)의 키를 확인하세요. |
| 403 | `API_ACCESS_REQUIRED` | 계정에 API 이용 권한이 없습니다. | Business 또는 Professional 패키지를 구매하세요. |
| 404 | `JOB_NOT_FOUND` | 작업이 없거나 다른 계정의 작업입니다. | ID를 확인하고 작업 생성 계정의 키를 사용하세요. |
| 409 | `JOB_CONFLICT` | 충돌로 작업을 생성하지 못했습니다. | 원래 멱등성 키로 재시도하세요. |
| 413 | `FILE_TOO_LARGE` | 파일이 4MB를 초과합니다. | 이미지 크기를 줄여 업로드하세요. |
| 429 | `RATE_LIMITED` | 최근 1분 동안 새 작업이 너무 많습니다. | `Retry-After`만큼 기다린 후 같은 키로 재시도하세요. |
| 429 | `CONCURRENCY_LIMITED` | 대기 중이거나 처리 중인 작업이 너무 많습니다. | 실행 중인 작업이 끝난 후 보내세요. |

크레딧 부족이나 인식 실패는 작업 수락 **후**에 발생할 수 있습니다. 업로드를 즉시 거부하는 대신 작업 조회에서 `status: "failed"`, `error.code`, `error.message`로 표시됩니다. 크레딧 부족 메시지가 있으면 잔액을 확인하세요.

## 제한 및 재시도

| 제한 | 값 |
| --- | --- |
| 계정별 새 작업 | 두 변환 엔드포인트 합계 분당 30개 |
| 동시 대기 또는 실행 작업 | Business: 3개, Professional: 10개 |
| 파일 크기 | 최대 4MB |
| 다운로드 URL 유효 시간 | 15분 |
| 결과 보관 기간 | 변환 성공 후 24시간 |

`429`에서는 `Retry-After`가 있으면 해당 시간만큼 기다리세요. 일시적 `5xx`나 네트워크 오류는 대기 시간을 단계적으로 늘리고 무작위 지연을 추가해 재시도하세요. 업로드 재시도에는 같은 멱등성 키를, 상태 조회에는 같은 작업 ID를 사용하세요. 애플리케이션에 전체 폴링 제한 시간을 설정하세요.

유효하지 않은 요청이나 인증 오류는 자동 재시도하지 말고 먼저 수정하세요. 문제가 계속되면 API 키나 다운로드 URL 없이 작업 ID와 오류 코드를 [지원팀](mailto:support@img2excel.net)에 전달하세요.

---

OpenAPI 3.1: https://img2excel.net/api/openapi.json
전체 API 문서: https://img2excel.net/ko/docs/api/text/llms-full.txt
