REST API
기본 주소 https://rerent.ai · 인증 Authorization: Bearer <토큰> (설정 → API 토큰) · 요청·응답 JSON · 시각은 epoch 초(분 단위 정렬, 60의 배수) · 금액·가격은 KRW 정수.
응답 규약: 단건은 { "object": "order", "id": "ordr_…", … }, 목록은 { "object": "list", "data": [...], "has_more": false, "cursor": null }. 오류는 { "error": { "code": "insufficient_balance", "message": "…" } }.
스케줄(*_allocation_schedule_delta)은 [{start_at, end_at, node_count}] 배열이고 응답에서는 마지막에 end_at: null, node_count: 0 종결자가 붙어요. 반열림 구간 [start_at, end_at).
계정
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/account | 조직·사용자·잔액·홀드·가용 |
| GET | /v1/stats/realized | 실현 할인 통계 + 공급자 매출 |
SKU
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/skus | 거래 중인 SKU. ?all=1 이면 중단 포함 |
| GET | /v1/skus/{id|alias} | 상세 |
| GET | /v1/skus/{id|alias}/availability?range_start_at&range_end_at | 살 수 있는 노드 수 스케줄(가격 무관) + 최저·최고 매도가 |
풀
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/pools?full=1 | 내 풀 목록(full이면 스케줄 포함) |
| POST | /v1/pools | {name} |
| GET | /v1/pools/{id|name} | 스케줄 · 매도 중 · 팔 수 있는 시간(SKU 별) |
| PATCH | /v1/pools/{id} | {name} |
| DELETE | /v1/pools/{id} | 열린 주문·남은 할당이 없을 때만 |
| GET | /v1/pools/{id}/sellable?sku= | 팔 수 있는 스케줄 |
| POST | /v1/pools/{id}/extend | {sku, duration_hours|end_at, max_price, allow_standing?, estimate?} |
| GET / POST | /v1/pools/transfers | {from_pool, to_pool, sku, start_at, end_at, node_count} |
| GET | /v1/pools/transfers/{id} |
주문
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/orders?side=&state=&pool=&limit=&starting_after=&fills=1 | 내 주문. state 반복 가능 |
| POST | /v1/orders | 주문 생성(아래) · Idempotency-Key 헤더 지원 |
| POST | /v1/orders/estimate | 같은 본문으로 견적(체결 없음) |
| GET | /v1/orders/{id} | 상세 + fills |
| POST | /v1/orders/{id}/cancel | 204 · 남은 부분만 취소 |
주문 본문:
{
"side": "buy", // buy | sell
"pool": "default", // 풀 ID 또는 이름
"sku": "icn-1-h100", // SKU ID 또는 alias
"start_at": "now", // epoch 초 또는 "now"
"end_at": 1789380000, // 또는 duration_hours
"node_count": 2,
"max_price": 30000, // buy: max_price · sell: min_price (또는 limit_price)
"allow_standing": false,
"allow_partial": false,
"memo": "nightly-train"
}
allocation_schedule_delta: [{start_at, end_at, node_count}] 한 구간으로 줘도 돼요(SF Compute 호환 꼴).
주문 응답의 주요 필드: state, allocation_schedule_delta(요청), remaining_allocation_schedule_delta(호가에 남은 것), filled_allocation_schedule_delta(체결된 것), fills[](각 체결의 price_krw_per_node_hour, gross_krw, fee_krw, net_krw, maker_side), filled_average_price_krw_per_node_hour.
오류 코드: insufficient_balance(402) · insufficient_allocation(409) · invalid_window · start_in_past · end_too_far · invalid_price · sku_not_found · pool_not_found · idempotency_mismatch(409).
공개 오더북(익명)
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/orderbook/summary | SKU 별 최저 매도·가능 노드·24h 체결 |
| GET | /v1/orderbook/windows?sku=&range_start_at=&range_end_at= | 열린 주문이 있는 SKU×윈도우와 best bid/ask |
| GET | /v1/orderbook/quote?sku=&start_at=&end_at= | 한 윈도우의 톱오브북 |
| GET | /v1/orderbook/depth?sku=&start_at=&end_at=&depth=20 | 가격 레벨별 노드 수 |
| GET | /v1/orderbook/fills?sku=&start_at=&end_at=&since_at=&limit= | 체결 내역 |
하드웨어 필터는 sku= 대신 requirements=accelerator:h100;region:kr 꼴도 받아요.
인스턴스(실행층)
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/instances | 목록(?pool=&state=&all=1) / 생성 {pool, sku?, count?, name?, image?, mode?, command?, startup_script?, env?, ports?, priority?} |
| GET / DELETE | /v1/instances/{id} | 단건 / 종료 |
| POST | /v1/instances/{id}/replace | 종료 + 같은 설정으로 새 인스턴스 대기열 |
| GET | /v1/instances/{id}/logs?tail= | 컨테이너 로그 |
| POST | /v1/instances/{id}/exec | {cmd, timeout_secs?} 명령 한 번(≤50초) |
| GET | /v1/instances/presets | (공개) 이미지 프리셋·기본값 |
| PATCH | /v1/pools/{id} | {launch_template:{enabled, image, mode, command?, startup_script?, env?, ports?, priority}} 자동 시작 |
| GET | /v1/nodes | 내 배정 노드(현재·예정) — 노드 상태·감지 GPU·그 위의 인스턴스와 ssh_command |
| GET / POST | /v1/ssh-keys · DELETE /v1/ssh-keys/{id} | 조직 SSH 공개키(돌고 있는 인스턴스에 즉시 반영) |
자동 매수(배포)
풀에 「이 SKU 노드 N대를 앞으로 H시간 동안 항상」 걸어 두면 매 분 보유 스케줄의 빈 구간을 상한가 이하 매물에서 즉시 사요(부분 체결 허용 · 호가에 남기지 않음). 공급자 자동 매도의 반대편이고, 풀의 자동 시작 템플릿과 함께 쓰면 사자마자 인스턴스가 떠요.
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/deployments | 목록(?pool=) / 생성 {pool, sku, name?, target_node_count, max_price, horizon_hours?=6, block_hours?=1, enabled?} |
| GET / PATCH / DELETE | /v1/deployments/{id|name} | 단건 / {enabled?, target_node_count?, max_price?, horizon_hours?, block_hours?, name?} / 중단(산 시간·주문은 남음) |
| POST | /v1/deployments/{id}/run | 지금 한 번 확보 시도(꺼져 있어도) → {bought_node_hours, buy_orders, error, deployment} |
horizon_hours1~168: 확보 기간 — 지금부터 몇 시간 앞까지 항상 확보해 둘지.block_hours1~24: 한 번에 사는 최소 길이 — 확보 기간 끝의 1분 조각이 매 분 1분짜리 매수가 되지 않게 블록마다 한 번 사요.- 응답
coverage: {now_nodes, horizon_covered_pct, next_gap_at}·spent_krw·bought_node_hours·buy_orders·last_error(크레딧 부족 · 상한가 이하 매물 없음 등 — 다음 분에 다시 시도). - 자동 매수 주문은
managed_by가 배포 id 예요(주문 목록에 「자동」 표시).
공급자
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/clusters | 목록 / 등록(응답 installs[] 에 노드별 설치 명령 install.shell(curl 한 줄 · 24시간 유효)·스크립트 주소 install.script_url · bootstrap 토큰 1회) |
| GET / PATCH / DELETE | /v1/clusters/{id} | PATCH {name?, auto_sell?, available_to_at?} |
| POST | /v1/clusters/{id}/nodes | {nodes:[…]} 또는 줄바꿈 문자열 → 응답 installs[] |
| POST | /v1/clusters/{id}/nodes/{nodeId}/install | 설치 명령 다시 받기(bootstrap 재발급 · 등록된 노드는 재설치용 새 호스트) |
| DELETE | /v1/clusters/{id}/nodes/{nodeId} | 노드 제거(구매자 인스턴스가 돌고 있으면 409) |
| GET | /v1/clusters/{id}/assignments | 노드별 배정(익명 꼬리표) |
크레딧·조직
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/credits/ledger | 원장 |
| GET / POST | /v1/credits/topups | 충전 요청 {amount_krw} |
| GET / POST | /v1/credits/payouts | 출금 요청 {amount_krw, bank_info} (소유자) |
| GET / POST | /v1/tokens · DELETE /v1/tokens/{id} | API 토큰 |
| GET | /v1/members · PATCH/DELETE /v1/members/{userId} | 멤버·역할 |
| POST | /v1/invites | {email, role} → 초대 링크 |
역할
| 역할 | 할 수 있는 것 |
|---|---|
| owner | 전부 + 출금 + 역할 변경 |
| admin | 매도·클러스터·토큰·초대·충전 요청 |
| member | 매수·조회 |
| viewer | 조회만(GET) |
API 토큰은 만들 때 고른 역할(admin·member·viewer)로 동작해요(기본 admin).
워크스페이스
조직 안에서 풀·인스턴스 템플릿·이미지를 묶는 단위예요(SF Compute workspaces). 인스턴스·주문·배포는 풀의 워크스페이스를 따라요. 조직마다 default 가 하나 있고 특별하지 않아요(이름 변경·삭제 가능 · 마지막 하나는 남음).
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/workspaces | 목록 / 생성 {name, description?} |
| GET / PATCH / DELETE | /v1/workspaces/{id|name} | 단건 / {name?, description?} / 삭제(풀·템플릿·이미지가 남아 있으면 409 workspace_not_empty) |
- 풀 생성 본문
workspace·PATCH /v1/pools/{id} {workspace}로 이동 · 목록 API 에?workspace=<id|name>필터(풀·인스턴스·주문·배포·템플릿·이미지). - 자원 경로(resource_path)
rerent:pool:<조직 slug>:<워크스페이스>:<이름>을 id 자리에 써도 돼요(풀·템플릿·이미지·배포).
태그
key=value 쌍으로 자원을 묶어요. 풀·주문·인스턴스·배포·클러스터·템플릿·이미지에 붙고, 생성 본문 tags: {key: value}(또는 ["key=value"]) · PATCH 로 전부 교체(tags: null 이면 모두 삭제).
- 규칙: 키 ≤128자(공백·쉼표·
=금지 ·_로 시작 금지) · 값 ≤256자(쉼표·=금지) · 자원당 50개 · 대소문자 구분. - 목록 필터:
?tag=env%3Dprod(반복 가능 · 모두 만족) ·?tag_key=team(키만). - 배포의 태그는 그 배포가 만드는 인스턴스·주문에도 붙어요.
한도
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/limits | 내 한도(limits)와 사용량(usage) · 화면용 items[] |
compute_max_total_node_hours: 전 풀 합계로 보유할 수 있는 노드·시간. 스케줄 아래 면적이라 멀리 사도 넓게 사도 같이 소모돼요.compute_node_hours_free_window_seconds(기본 1시간) 안은 세지 않아요.- 넘기는 매수 주문은 403
limit_exceeded로 거절되고 주문이 만들어지지 않아요(견적은 통과 · 매도는 한도로 거절되지 않아요). - 개수 한도: 풀·워크스페이스·열린 주문·주문 하나의 노드 수·살아 있는 인스턴스·템플릿·이미지·SSH 키·API 토큰·클러스터·노드·배포·웹훅. 상향은 support@rerent.ai.
인스턴스 템플릿
재사용 가능한 인스턴스 설정(불변 — 바꾸려면 새 이름으로). 배포가 인스턴스를 만들 때 쓰고, POST /v1/instances {template} 로 사람도 써요.
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/instance-templates?workspace=&tag= | 목록 / 생성 {name, image, mode?, command?, startup_script?, env?, ports?, priority?, ssh_allow_cidrs?, tags?, workspace?, description?} |
| GET / PATCH / DELETE | /v1/instance-templates/{id|name} | 단건 / {tags?, description?} 만 / 삭제(배포·살아 있는 인스턴스가 쓰면 409 template_in_use) |
image에 이미지 카탈로그 이름(trainer)을 쓰면 참조·자격증명이 붙어요.ssh_allow_cidrs: SSH 접속을 허용할 IPv4 대역(203.0.113.0/24). 비우면 어디서나(키 있는 사람만). 컨테이너 sshd 의Match Address규칙으로 적용돼요 — 노출 포트(ports)에는 적용되지 않아요.- 인스턴스 생성 시
template+ 다른 필드를 함께 보내면 요청 값이 템플릿을 덮어써요.priority_level: yield|normal|preferred|critical도 받아요(= priority 1~4).
이미지 카탈로그
조직이 이름 붙여 둔 도커 이미지 참조(+비공개 레지스트리 자격증명). Rerent 는 컨테이너라 레지스트리 참조가 곧 이미지예요(SF Compute 의 디스크 이미지 업로드는 없음).
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/images?workspace=&tag=&status=&include_public=1 | 목록(+공개 프리셋) / 등록 {name, image_ref, description?, registry_auth?: {registry?, username, password}, tags?, workspace?} |
| GET / PATCH / DELETE | /v1/images/{id|name} | 단건 / {description?, tags?, registry_auth?|null} / 삭제(살아 있는 인스턴스·템플릿이 쓰면 409) |
| POST | /v1/images/{id}/revoke · /reinstate | 회수(새 인스턴스에 못 씀 · 돌던 것은 그대로) / 복구 |
- 자격증명은 응답에 절대 나오지 않고, 컨테이너 기동 때 노드 에이전트가 격리된 임시 도커 설정으로 로그인해 pull 하는 데만 써요.
- 회수된 이미지를 가리키는 템플릿·인스턴스 생성은 400
image_revoked.
인스턴스 추가 API
| 메서드 | 경로 | 설명 |
|---|---|---|
| PATCH | /v1/instances/{id} | {name?, priority?|priority_level?, tags?} — 그 밖의 설정은 불변(교체로) |
| PATCH | /v1/instances | {ids: […], priority?|priority_level?, tags?} 여러 개 한 번에 — 전부 성공 아니면 전부 실패 |
| GET | /v1/instances/{id}/ssh | 접속 정보(host·port·command·allowed_cidrs·등록 키 지문) — 실행 중 ssh 모드에서만 |
| GET | /v1/instances?deployment=&workspace=&tag= | 배포·워크스페이스·태그 필터 |
| GET | /v1/skus/availability?range_start_at&range_end_at&requirements= | (공개) 전 SKU 가용 스케줄 한 번에 |
| GET | /v1/users · /v1/users/{id|email} | 조직 사용자(/v1/members 와 같은 데이터) |
인스턴스 응답에 tags · template {id,name} · image_catalog {id,name,revoked} · deployment {id,name,kind} · managed_by · priority_level · ssh_allow_cidrs 가 추가됐어요.
배포(deployments) — generic · spot
배포는 풀 위에서 인스턴스 무리를 목표 수만큼 유지하는 자동화예요(SF Compute deployments / spot deployments).
| kind | 하는 일 |
|---|---|
spot(기본) | 목표 노드 수를 확보 기간(앞으로 horizon_hours시간) 안에서 항상 확보하도록 상한가 이하 매물을 매 분 매수(부분 허용 · 호가에 남기지 않음) + template 이 있으면 산 노드에 인스턴스를 목표 수만큼 유지 |
generic | 매수 없음. 이미 산 시간 위에서 template 으로 인스턴스 수만 목표에 맞춤(템플릿 필수) |
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET / POST | /v1/deployments?pool=&kind=&workspace=&tag= | 목록 / 생성 {pool, sku, kind?, name?, target_node_count(=target_instance_count), max_price(spot), horizon_hours?=6, block_hours?=1 (또는 min_runtime_minutes), template?, instance_name_template?, tags?, enabled?} |
| GET / PATCH / DELETE | /v1/deployments/{id|name} | 단건 / 같은 필드 / 삭제(generic 은 관리 인스턴스 전부 종료 · spot 은 돌고 있는 것은 두고 더 사지 않음) |
| POST | /v1/deployments/{id}/run | (spot) 지금 한 번 매수 시도 |
- 풀×SKU 조합마다 배포는 하나만(409
duplicate_pool_sku). - 인스턴스 이름 템플릿
{{adjective}}-{{noun}}-{{nanoid(6)}}(기본) ·{{nanoid(n)}}필수 · 결과는 32자 이내. - 목표를 줄이면 우선순위 낮은 것·최근 것부터 종료. 사람이 인스턴스를 종료하면 다음 조정(1분 안)에서 채워요. 일시 정지(
enabled:false)는 대기 인스턴스만 내리고 돌고 있는 것은 그대로. - 응답
instances {awaiting, running, target}·status {state: info|warning|error, message}·min_runtime_minutes·instance_template·tags. - 주문 목록
?deployment=<id|name>으로 배포가 낸 주문만,?managed=0으로 자동 주문 제외.
이벤트 · 웹훅
조직에서 일어난 일이 이벤트로 기록되고(GET), 웹훅으로 내 서버에 POST 돼요. SF Compute 에는 없는 기능이에요.
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/events?type=&object_id=&limit=&starting_after=evt_… | 활동 기록(최근순 · 커서) + types[] 카탈로그 |
| GET / POST | /v1/webhooks | 목록 / 생성 {url(https), event_types?: [] (비우면 전부), description?, enabled?} → secret 은 지금 한 번만 |
| GET / PATCH / DELETE | /v1/webhooks/{id} | 단건 / {url?, event_types?, description?, enabled?} / 삭제 |
| POST | /v1/webhooks/{id}/test | webhook.test 이벤트를 바로 보내고 결과 {ok, status, error} |
| GET | /v1/webhooks/{id}/deliveries | 배달 기록(상태·시도·오류·다음 재시도) |
이벤트 종류: order.filled order.partially_filled order.standing order.cancelled order.fill(내 호가가 체결됨 · 메이커) instance.created instance.running instance.failed instance.terminated deployment.bought deployment.error deployment.scaled node.online node.offline node.assigned topup.confirmed payout.paid webhook.test.
배달: POST <url> · 본문 {id, type, label, object_type, object_id, data, created_at, org_id, webhook_id, api_version} · 헤더 Rerent-Event · Rerent-Event-Id · Rerent-Signature: t=<epoch>,v1=<hex> (v1 = HMAC-SHA256(secret, "<t>.<본문>") · 5분 안의 t 만 받아요). 2xx 가 아니면 1·5·30분·2시간 뒤 다시 보내고 5회 뒤 포기(failures 증가).
// 수신 서버(Node) 검증 예
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(secret, rawBody, header) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header || ''); if (!m) return false
if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false
const want = createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex')
return timingSafeEqual(Buffer.from(want, 'hex'), Buffer.from(m[2], 'hex'))
}
토큰 역할
POST /v1/tokens {name, role?: admin|member|viewer, expires_days?} — admin(기본 · 전부) · member(매수·인스턴스·조회 · 매도·토큰·클러스터 불가) · viewer(GET 만 · 변경 요청은 403 read_only). 멤버 역할에도 viewer 가 추가됐고(PATCH /v1/members/{id} {role} · 초대 role), GET /v1/account 에 read_only · default_workspace_id 가 있어요.