본문으로 건너뛰기

Jobs API 사용하기

API 키로 잡을 제출하고 상태를 읽고 로그와 결과물을 받는 HTTP 호출을 요청과 응답 예시로 설명합니다

러너 API는 https://xenoci.com/api/runner/v1 아래에 있고 모든 요청은 Authorization: Bearer xci_live_… 헤더 하나로 인증합니다

기본 규칙

항목값
기본 URLhttps://xenoci.com/api/runner/v1
인증Authorization: Bearer <API 키> (키는 콘솔 API 키 메뉴에서 발급)
본문JSON, 최대 64KB (업로드만 application/octet-stream)
응답 헤더X-Request-Id (문의할 때 함께 보내는 요청 번호)
멱등쓰기 요청에 Idempotency-Key 헤더(1~255자)를 보내면 24시간 안의 같은 요청은 같은 잡을 돌려주고, 본문이 다르면 409 idempotency_conflict
오류 봉투{ "error": { "code", "message", "retryable", "retry_after_s", "fault", "request_id", "docs_url", "details" } }

read 권한 키는 GET만 할 수 있습니다

POST를 보내면 403 insufficient_permission입니다

키는 자기 워크스페이스에서만 동작하므로 workspace_id는 생략하거나 키의 워크스페이스와 같아야 합니다

1. 잡 제출

curl -s https://xenoci.com/api/runner/v1/jobs \
  -H "Authorization: Bearer $XENOCI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "script": "xcodebuild -version\nsw_vers",
    "xcode": "27.0",
    "timeout_minutes": 20,
    "source_kind": "api"
  }'

요청 본문 필드

필드형식설명
script문자열, 1~65,536자, 필수VM에서 bash -eo pipefail로 실행할 셸 스크립트
source객체{ "upload_id": "upl_…" } 또는 { "git_url": "https://…", "ref": "main" } 없으면 빈 작업 폴더에서 시작
xcode문자열27.0 또는 26.6 없으면 워크스페이스 기본값, 그것도 없으면 이미지 기본값 27.0
timeout_minutes정수 1~360기본 60 스크립트 시작 후 이 시간이 지나면 timed_out
env객체환경 변수 최대 100개, 이름은 [A-Za-z_][A-Za-z0-9_]{0,127}, 값은 32,768자 이하
artifacts문자열 배열, 최대 50개끝난 뒤 모을 경로 글롭 (build/*.ipa)
repository문자열, 200자 이하owner/name 사용량 CSV 표시용
source_kindcli, mcp, github_action, api잡 출처 표시 기본 api
recipe_id문자열레시피로 스크립트를 채울 때 script와 함께 보낼 수 없음
workspace_id문자열콘솔 세션만 필수 키는 생략

응답은 201과 잡 객체입니다

막 접수된 잡은 queued이고 수 초 안에 빈 슬롯을 받습니다

{
  "id": "job_7Kp2QmX9bT4vR1sLwZ3n",
  "organization_id": "org_b1Y4kP",
  "workspace_id": "wrk_Hq8sN2",
  "api_key_id": "key_c3Tt9x",
  "status": "queued",
  "queued_reason": "capacity",
  "end_reason": null,
  "error": null,
  "exit_code": null,
  "created_at": "2026-10-12T03:10:00.000Z",
  "started_at": null,
  "ended_at": null,
  "run_seconds": null,
  "billed_minutes": null,
  "rate_micro_usd_per_min": 39600,
  "rate_usd_per_min": "0.039600",
  "amount_micro_usd": 0,
  "amount_usd": "0.000000",
  "credit_low": null,
  "log_url": "/api/runner/v1/jobs/job_7Kp2QmX9bT4vR1sLwZ3n/logs",
  "repository": null,
  "source_kind": "api"
}

금액은 항상 두 필드로 옵니다

*_micro_usd는 정수 µUSD(1 USD = 1,000,000)로 계산용이고 *_usd는 같은 값의 소수 6자리 문자열로 표시용입니다

2. 잡 읽기

curl -s https://xenoci.com/api/runner/v1/jobs/job_7Kp2QmX9bT4vR1sLwZ3n \
  -H "Authorization: Bearer $XENOCI_API_KEY"

끝난 잡은 status가 종료 상태로 바뀌고 run_seconds, billed_minutes, amount_usd가 채워집니다

{
  "id": "job_7Kp2QmX9bT4vR1sLwZ3n",
  "status": "succeeded",
  "end_reason": "succeeded",
  "exit_code": 0,
  "started_at": "2026-10-12T03:10:41.000Z",
  "ended_at": "2026-10-12T03:12:46.000Z",
  "run_seconds": 125,
  "billed_minutes": 3,
  "rate_usd_per_min": "0.039600",
  "amount_usd": "0.118800"
}

3. 잡 목록

curl -s "https://xenoci.com/api/runner/v1/jobs?status=failed&limit=20" \
  -H "Authorization: Bearer $XENOCI_API_KEY"
쿼리설명
status상태 하나로 거름
limit1~100, 기본 20
cursor이전 응답의 next_cursor (잡 ID)

응답은 { "data": [잡…], "next_cursor": "job_…" 또는 null }이고 최신순입니다

4. 로그 읽기

curl -s "https://xenoci.com/api/runner/v1/jobs/job_7Kp2QmX9bT4vR1sLwZ3n/logs?offset=0" \
  -H "Authorization: Bearer $XENOCI_API_KEY" -D -

본문은 text/plain이고 응답 헤더 X-Log-Next-Offset이 다음 호출의 offset, X-Log-Complete가 잡 종료 여부입니다

자세한 폴링 방법은 로그 스트리밍에 있습니다

5. 취소

curl -s -X POST https://xenoci.com/api/runner/v1/jobs/job_7Kp2QmX9bT4vR1sLwZ3n/cancel \
  -H "Authorization: Bearer $XENOCI_API_KEY"

대기 중이면 바로 cancelled, 실행 중이면 스크립트를 멈춘 뒤 cancelled가 되고 이미 끝난 잡은 409 conflict입니다

6. 결과물

curl -s https://xenoci.com/api/runner/v1/jobs/job_7Kp2QmX9bT4vR1sLwZ3n/artifacts \
  -H "Authorization: Bearer $XENOCI_API_KEY"

목록의 각 항목을 GET /v1/jobs/{job_id}/artifacts/{artifact_id}로 부르면 15분짜리 다운로드 URL로 302 리다이렉트합니다

결과물을 보세요

오류 코드

HTTP코드뜻
400invalid_request본문 검증 실패 details.fields에 필드 이름
401api_key_required, invalid_api_key, api_key_revoked_leaked키 없음, 폐기됨 또는 공개 유출로 자동 폐기됨
402insufficient_credit사용 가능 잔액이 1분 요금 미만 details.topup_url에 충전 링크
402workspace_spend_limit, tier_monthly_limit워크스페이스 또는 티어 월 한도 도달 details.resets_at에 해제 시각
403insufficient_permission, workspace_archived읽기 키로 쓰기 요청, 다른 워크스페이스, 보관된 워크스페이스
404not_found없는 잡이거나 이 키가 볼 수 없는 잡
409conflict, idempotency_conflict상태가 맞지 않음, 같은 키에 다른 본문
429tier_concurrency_limit, rate_limited동시 실행 한도와 대기열 모두 가득 Retry-After 헤더
503capacity_unavailable러너 용량 없음 retry_after_s 뒤 재시도

같은 흐름을 CLI로 하려면 다음 한 줄이면 됩니다

npx -y -p github:xeno-ci/xenocast xenocast build --script ./ci.sh --xcode 27.0 --timeout 20

다음 단계