Skip to Content
문서엔드포인트

API

이 문서는 Deplite의 공개 REST API를 정리해요.
프로그램(외부 시스템, CI, 자체 스크립트, 자체 Agent)에서 호출하는 모든 엔드포인트가 대상이에요.

조직·트리거·토큰의 생성과 관리는 대시보드(deplite.io)에서 진행해요.
이 문서는 대시보드에서 받은 트리거 ID와 API Token으로 어떻게 호출하는지에 집중해요.

인증 방식

방식헤더용도
API TokenAuthorization: Bearer dpl_...외부 시스템·CI·자동화 스크립트
Agent 서명X-Agent-Id, X-Timestamp, X-Nonce, X-Signature자체 구현 Agent ↔ Server

API Token은 대시보드에서 scope(agent / trigger / storage)와 rate limit을 지정해 발급받아요.
평문 토큰은 발급 시점에만 한 번 보이고, 이후엔 복원할 수 없어요.
안전한 비밀 저장소에 보관하세요.

토큰 scope 종류

토큰의 scopes는 grant 배열이고, 각 type은 최대 하나씩 들어가요.

type형태의미
agent{ type: 'agent', agentIds: string[] }지정한 Agent에 대한 권한
trigger{ type: 'trigger', triggerIds: string[] }지정한 트리거 실행 권한
storage{ type: 'storage', bindingIds: string[] | null, permissions: ('read' | 'write' | 'delete')[] }지정한 storage binding 접근 권한 (bindingIds: null이면 조직 전체 binding)

Base URL

  • API: https://api.deplite.io/v1

모든 경로는 위 베이스에 붙여서 호출해요.
이 문서의 경로 표는 베이스 이후의 path만 표기해요.

토큰 접근 범위 조회

토큰이 실제로 무엇에 닿을 수 있는지 토큰 스스로 알려주는 조회 엔드포인트예요.
예전에는 API Token 보유자가 트리거·워크플로우 ID를 항상 외부에서 미리 알고 있어야 했는데, ID는 비밀이 아니므로 grant 범위 안에서의 열거를 허용해 사용성을 개선한 거예요.

메서드경로인증설명
GET/tokenAPI Token (scope 무관)토큰 자기소개
GET/agentsAPI Token (scope 무관)접근 가능한 device 목록
GET/devicesAPI Token (scope 무관)/agents의 alias, 응답 동일
GET/workflowsAPI Token (scope 무관)실행 가능한 워크플로우 목록

네 엔드포인트 모두 Authorization: Bearer dpl_...만 있으면 호출할 수 있고, 특정 scope를 요구하지 않아요.

응답은 그 토큰의 grant 범위로만 한정돼요.
조직 전체 인벤토리를 돌려주지 않고, 새로운 권한을 부여하지도 않아요.
이미 그 토큰으로 호출할 수 있는 대상만 열거해서 보여주는 엔드포인트예요.

GET /token

호출자가 이미 토큰을 쥐고 있으므로, 그 토큰의 메타만 그대로 돌려줘요.

curl https://api.deplite.io/v1/token \ -H "Authorization: Bearer dpl_..."
{ "name": "CI/CD", "scopes": [ { "type": "agent", "agentIds": ["a-1111"] }, { "type": "storage", "bindingIds": null, "permissions": ["read", "write"] } ], "rateLimit": { "perMinute": 10, "perHour": 100, "perDay": 1000 }, "expiresAt": "2026-12-31T23:59:59Z" }

평문 토큰이나 해시는 응답에 포함되지 않아요.

GET /agents · GET /devices

두 경로는 완전히 같은 응답을 돌려주는 alias예요.
토큰이 닿을 수 있는 device를 최근 등록 순으로 나열해요.

curl https://api.deplite.io/v1/agents \ -H "Authorization: Bearer dpl_..."
[ { "id": "a-1111", "name": "prod-seoul-01", "hostname": "ip-10-0-1-23", "os": "linux", "agentVersion": "0.1.1", "status": "connected", "lastSeenAt": "2026-07-09T02:31:04Z", "enrolledAt": "2026-05-02T08:12:00Z" } ]
필드타입설명
idUUIDAgent(device) ID
namestring대시보드에서 지정한 이름
hostnamestringAgent가 보고한 호스트명
osstringAgent가 보고한 OS
agentVersionstringAgent 버전
statuspending | connected | disconnected | revoked현재 연결 상태
lastSeenAttimestamp마지막 하트비트 시각
enrolledAttimestamp등록 완료 시각

GET /workflows

토큰으로 실행할 수 있는 워크플로우를 이름 오름차순으로 나열해요.

curl https://api.deplite.io/v1/workflows \ -H "Authorization: Bearer dpl_..."
[ { "id": "w-2222", "agentId": "a-1111", "name": "deploy", "description": "프로덕션 배포", "version": "1.2.0", "paramsSchema": [ { "name": "env", "type": "enum", "required": true, "options": ["staging", "prod"] } ] } ]
필드타입설명
idUUID워크플로우 ID
agentIdUUID이 워크플로우가 속한 Agent
namestring워크플로우 이름. 트리거 호출 시 workflowName으로 넘기는 값
descriptionstring | null워크플로우 설명
versionstring | nullAgent가 워크플로우 정의에서 보고한 자유 문자열. semver를 강제하지 않아 "1.2.0", "2024-06-rc1" 같은 임의 값이 올 수 있고, 정의에 없으면 null
paramsSchemaarray | null입력 파라미터 정의 배열. 각 항목은 name·type(string | number | boolean | enum)을 갖고, required·default·pattern·options·min·max·description이 선택으로 붙어요

removed 상태(제거된) 워크플로우는 목록에 나오지 않아요.

grant → 노출 범위 매핑

/agents/workflows가 무엇을 보여줄지는 토큰의 grant 조합으로 결정돼요.

토큰이 가진 grant/agents에 보이는 것/workflows에 보이는 것
agent grantgrant에 적힌 Agent그 Agent의 모든 active 워크플로우
trigger grant — 트리거가 scopeType: agent트리거가 가리키는 Agent그 Agent의 모든 active 워크플로우
trigger grant — 트리거가 scopeType: workflow트리거가 가리키는 Agent그 트리거의 워크플로우 1개
storage grant만 있는 토큰빈 배열빈 배열

응답에서 의도적으로 빠지는 필드

민감 정보 누출을 막기 위해 아래 필드는 어떤 경우에도 응답에 담기지 않아요.

리소스제외되는 필드
AgentpublicKey
TriggertokenHash
Workflowsecrets, secretsKeys, steps

paramsSchema는 비밀이 아니라 입력 파라미터 정의라서, 호출 편의를 위해 포함돼요.

에러와 rate limit

HTTP상황
401토큰 누락 / 무효 / 폐기됨 / 만료됨
429읽기 rate limit 초과

읽기 rate limit은 토큰의 rateLimitPerMinute(Job 디스패치 한도)와는 별개예요.
기본값은 토큰당 분당 60회이고, 서버 환경변수 API_TOKEN_READ_RATE_LIMIT_PER_MINUTE로 조정해요.

{ "statusCode": 429, "error": "Too Many Requests", "message": "Rate limit exceeded for api token reads (minute: 61/60)", "scope": "token_read", "window": "minute", "limit": 60, "observed": 61 }

셀프 호스팅 운영 주의: 이 카운터는 인스턴스 메모리에 있어서, 다중 인스턴스 배포에서는 인스턴스당 한도로 동작해요.
전역 한도가 아니라 열거(enumeration) 폭주를 늦추는 완화책으로 봐주세요.

감사 로그

호출남는 audit 로그
/agents, /devices, /workflowsapi_token.discover (metadata: { resource, count })
/token기록하지 않음
읽기 rate limit에 걸린 호출rate_limit.block (scope: 'token_read'), 토큰당 윈도우 1회만 기록

rate_limit.block을 윈도우당 1회로 제한하는 이유는, 폭주하는 호출이 audit 테이블에 쓰기 증폭을 일으키지 않도록 하기 위해서예요.

Trigger 실행

메서드경로인증설명
POST/triggers/:id/runAPI Token (trigger scope)Webhook 실행

POST /triggers/:id/run

curl -X POST https://api.deplite.io/v1/triggers/<id>/run \ -H "Authorization: Bearer dpl_..." \ -H "Idempotency-Key: <unique>" \ -d '{ "ref": "main", "debug": false, "workflowName": "deploy", "params": { "env": "prod" } }'

요청 본문 필드:

필드타입설명
refstring, 선택호출자 측에서 식별·로깅에 쓰는 ref (1–255자). 보통 git SHA / 태그
debugboolean, 선택디버그 모드 실행
paramsobject, 선택워크플로우 step에 그대로 전달되는 임의 페이로드
workflowNamestring, 선택scopeType: agent인 트리거에서는 필수, scopeType: workflow에선 무시

응답 (async, responseMode: async):

{ "jobId": "j-abc-1234", "status": "pending", "statusUrl": "/api/jobs/j-abc-1234" }

응답 (sync, responseMode: sync):

{ "jobId": "j-abc-1234", "status": "success", "exitCode": 0, "errorMessage": null, "output": { "deployedRef": "main-7f3a9b" }, "statusUrl": "/api/jobs/j-abc-1234" }

Idempotency-Key가 이전 호출과 같으면 같은 jobId"idempotent": true 플래그를 붙여 돌려줘요.
sync 모드에서 responseTimeoutMs를 초과한 경우 "timedOut": true가 붙고 워크플로우는 백그라운드에서 계속 진행돼요.

statusUrl/api/jobs/...는 대시보드 콘솔 URL이라 API Token으로는 호출할 수 없어요.
외부에서 결과를 받는 방법은 두 가지예요.
responseMode: sync 트리거로 만들어 /run 응답에서 바로 꺼내 쓰거나, 트리거의 notify… 옵션으로 Slack/Discord 알림을 받는 방식이에요.
공개 v1 API에는 GET /jobs/... 엔드포인트가 없으니, Job 상세는 대시보드 Jobs 화면에서 확인해주세요.

File Storage

외부 시스템(CI 파이프라인 등)이 파일을 업로드·교환할 때 쓰는 공개 API예요.
인증은 storage 스코프가 부여된 API Token이며, 토큰은 하나 이상의 storage binding에 묶여 있어요.

메서드경로인증설명
POST/storage/files/presign-uploadstorage 스코프 + write업로드 사전 서명 URL 발급
POST/storage/files/:id/completestorage 스코프 + write업로드 완료 통지
GET/storage/files/:id/download-urlstorage 스코프 + read다운로드 사전 서명 URL
GET/storage/files/:idstorage 스코프 + read파일 메타
GET/storage/filesstorage 스코프 + read파일 목록 (최대 200건)
DELETE/storage/files/:idstorage 스코프 + delete파일 삭제

storage 스코프 토큰은 발급 시 { type: 'storage', bindingIds: [...], permissions: ['read', 'write', 'delete'] } 형태로 binding과 허용 권한을 함께 지정해요.
권한은 배열이라 read 전용 / read+write / 전체 등 자유 조합이 가능해요.

POST /storage/files/presign-upload

요청 본문:

{ "bindingId": "<uuid, 선택>", "filename": "release.apk", "contentType": "application/vnd.android.package-archive", "cleanupRule": "ttl", "ttlSeconds": 604800 }
필드타입설명
bindingIdUUID, 선택어느 storage binding을 쓸지. 토큰이 단일 binding만 허용한다면 생략 가능
filenamestring, 선택원본 파일명 힌트 (max 255)
contentTypestring, 선택MIME 타입 (max 255)
cleanupRule"ttl" | "persistent", 필수외부 API는 on_job_end 미지원
ttlSecondsint, 선택cleanupRule: ttl일 때 60 ~ 90일 사이

응답:

{ "fileId": "f-abc-1234", "uploadUrl": "https://...presigned...", "method": "PUT", "headers": { "Content-Type": "application/vnd.android.package-archive" }, "expiresInSeconds": 900 }

받은 uploadUrl로 곧바로 PUT 한 뒤, 같은 fileId/complete를 호출해야 파일이 active 상태가 돼요.

POST /storage/files/:id/complete

본문 없이 호출해요.
응답은 아래 메타 스키마와 동일해요.

GET /storage/files/:id/download-url

{ "downloadUrl": "https://...presigned...", "expiresInSeconds": 900 }

다운로드 URL은 매 호출마다 새로 발급돼요.
워크플로우에 넘길 때는 호출 직전에 받아 params로 전달하세요.

GET /storage/files

쿼리:

파라미터설명
bindingIdUUID, 단일 binding으로 필터
statuspending | active | deleting | deleted | delete_failed

응답은 메타 배열이에요 (최대 200건).

파일 메타 응답 스키마

{ "id": "f-abc-1234", "bindingId": "sb-...", "filename": "release.apk", "contentType": "application/vnd.android.package-archive", "size": 28473921, "status": "active", "cleanupRule": "ttl", "expiresAt": "2026-06-09T12:00:00Z", "deletedAt": null, "createdAt": "2026-06-02T12:00:00Z" }

외부 API 응답에는 organizationId·jobId 같은 내부 필드가 빠져 있어요.
토큰의 binding 권한 범위에서만 메타가 보여요.

App Deploy (OTA)

기존 트리거 배포는 서버가 Agent에게 실행을 밀어 넣는 방식이라, Agent가 오프라인이면 그 실행은 곧바로 거절돼요.
App Deploy(OTA)는 Deplite가 배포 서버 역할을 맡아 아티팩트를 조직 스토리지에 보관하고, 기기가 온라인이 될 때 스스로 최신 릴리스로 수렴하게 해요.
키오스크처럼 항상 켜져 있지 않은 기기에 배포할 때 참고해주세요.

설치·재시작 같은 적용 로직은 여전히 여러분의 로컬 워크플로우(예: app-update)에만 있어요.
서버는 “이 아티팩트를 파라미터로 넣어 기기의 로컬 워크플로우를 실행한다”까지만 관여하고, 어떻게 적용할지는 워크플로우가 결정해요.

인증과 경로

App Deploy 엔드포인트는 두 부류로 나뉘어요.

부류인증경로
대시보드 관리대시보드 로그인 세션(JWT) + 조직 role/orgs/:orgId/apps/...
Agent 배포Agent 서명 (X-Agent-Id, X-Timestamp, X-Nonce, X-Signature)/agent/deploy/... (베이스 https://api.deplite.io/v1)

대시보드 관리 엔드포인트는 앱·릴리스·기기를 만들고 운영하는 콘솔 API예요.
조직 role로 인가되고, 삭제처럼 되돌리기 어려운 작업은 owner만 할 수 있어요.

앱 (Apps)

메서드경로인증설명
GET/orgs/:orgId/apps세션 + 조직 role앱 목록
POST/orgs/:orgId/apps세션 + 조직 role앱 생성
GET/orgs/:orgId/apps/:appId세션 + 조직 role앱 상세
PATCH/orgs/:orgId/apps/:appId세션 + 조직 role앱 수정
DELETE/orgs/:orgId/apps/:appId세션 + owner앱 삭제

앱을 만들 때 지정하는 값이에요.

필드타입설명
slugstring조직 안에서 유일한 앱 식별자
updateWorkflowNamestring업데이트를 적용할 로컬 워크플로우 이름 (예: app-update)
defaultChannelstring기기가 구독할 기본 채널. 기본값은 stable

릴리스 (Releases)

메서드경로인증설명
GET/orgs/:orgId/apps/:appId/releases세션 + 조직 role릴리스 목록 (?channel=&status=)
POST/orgs/:orgId/apps/:appId/releases세션 + 조직 role릴리스 생성 (draft)
GET/orgs/:orgId/apps/:appId/releases/:releaseId세션 + 조직 role릴리스 상세
POST/orgs/:orgId/apps/:appId/releases/:releaseId/publish세션 + 조직 role게시
POST/orgs/:orgId/apps/:appId/releases/:releaseId/yank세션 + 조직 role회수(롤백)

릴리스는 아티팩트(스토리지 파일)를 가리키는 배포 단위예요.
게시(publish)하면 그 채널의 기기들이 다시 평가되어 최신 릴리스로 수렴하기 시작해요.
회수(yank)하면 대상 채널의 desired가 직전 게시본으로 내려가고, 기기들이 그쪽으로 수렴해요(다운그레이드).
회수는 롤백 수단이므로, 로컬 워크플로우가 다운그레이드를 감당할 수 있는지 확인해주세요.

게시된 릴리스는 불변이에요.
순서는 사람이 읽는 version 문자열이 아니라 앱 단위로 증가하는 sequence로 판단해요.
updatePolicymandatory인 릴리스는 최소 버전 마커가 되어, 그보다 낮은 기기는 강제로 업데이트돼요.
optional이면 최신으로 수렴하되 기기가 미룰 수 있어요.

릴리스용 아티팩트는 cleanupRule: 'persistent'로 업로드해야 릴리스 생성이 통과해요.
릴리스가 참조 중인 파일은 삭제가 409로 막혀요.
그 파일을 지우려면 해당 릴리스를 먼저 회수(yank)해주세요.

기기 (Devices)

메서드경로인증설명
GET/orgs/:orgId/apps/:appId/devices세션 + 조직 role기기(바인딩) 목록
POST/orgs/:orgId/apps/:appId/devices세션 + 조직 role앱에 Agent 바인딩
PATCH/orgs/:orgId/apps/:appId/devices/:deviceId세션 + 조직 role기기 채널 변경
DELETE/orgs/:orgId/apps/:appId/devices/:deviceId세션 + 조직 role바인딩 해제
POST/orgs/:orgId/apps/:appId/devices/:deviceId/reconcile세션 + 조직 role수동 재평가

기기는 앱과 Agent를 묶은 바인딩이고, 관측된 현재 설치본과 희망 릴리스 상태를 담아요.
바인딩을 만들 때 channel을 생략하면 앱의 기본 채널을 따라요.
reconcile은 기기의 desired를 지금 다시 계산해서 필요하면 업데이트 job을 다시 발생시키는 수동 재평가예요.

기기 바인딩 요청 본문:

{ "agentIds": ["a-1111", "a-2222"], "channel": "stable" }

채널 변경 요청 본문:

{ "channel": "beta" }
필드타입설명
agentIdsstring[]앱에 바인딩할 Agent ID 목록
channelstring, 선택구독할 채널. 생략하면 앱의 기본 채널

OTA 업데이트 job은 트리거로 생성되지 않아 triggerId가 없어요.
그래서 트리거 job 목록(GET /orgs/:orgId/jobs)에는 나타나지 않아요.
진행 중인 job은 기기의 activeJobId로 해당 job 상세(GET /jobs/:id)에 접근해주세요.

Agent 배포 엔드포인트

Agent가 자기 배포 상태를 확인하고 보고하는 엔드포인트예요.
Agent 서명으로 인증해요.

메서드경로인증설명
GET/agent/deploy/desiredAgent 서명각 앱의 서명된 desired 매니페스트
POST/agent/deploy/reportAgent 서명현재 설치 상태 보고
curl https://api.deplite.io/v1/agent/deploy/desired \ -H "X-Agent-Id: <agentId>" \ -H "X-Timestamp: <timestamp>" \ -H "X-Nonce: <nonce>" \ -H "X-Signature: <signature>"

응답은 Agent가 담당하는 앱마다 서명된 매니페스트 1개를 담아요.

{ "apps": [{ "payload": { "application_id": "...", "slug": "kiosk", "channel": "stable", "update_workflow": "app-update", "current": { "release_id": "...", "version": "1.1.0", "sequence": 1 }, "desired": { "release_id": "...", "version": "1.2.0", "sequence": 2, "channel": "stable", "workflow_name": "app-update", "checksum_sha256": "...", "size": 10485760, "download_url": "https://...", "download_expires_in": 900 }, "min_version": "1.2.0", "min_sequence": 2, "forced": true, "issued_at": 1750000000, "nonce": "..." }, "signature": "<base64 서명>" }]}

current는 서버가 관측한 현재 설치본, desired는 기기가 수렴해야 할 목표 릴리스예요.
signaturepayload를 canonical JSON으로 직렬화한 값에 대한 서명이에요.
Agent는 등록(enroll) 때 받은 서버 공개키(serverPublicKey)로 이 서명을 검증해요.
download_url은 매 발급마다 새로 만들어지고 download_expires_in(초) 뒤 만료돼요.
이 매니페스트는 서버가 밀어 준 job의 pull 폴백이자 Agent 자가 점검용이니 참고해주세요.

report는 Agent가 관측한 현재 설치 상태를 보고하는 엔드포인트예요.

{ "applicationId": "...", "currentVersion": "1.1.0", "currentReleaseId": "...", "currentSequence": 1, "state": "idle", "error": null }
필드타입설명
applicationIdstring보고 대상 앱
currentVersionstring, 선택현재 설치된 버전 라벨
currentReleaseIdstring, 선택현재 설치된 릴리스
currentSequenceint, 선택현재 설치된 릴리스의 순서 값
statestring, 선택기기가 관측한 적용 상태
errorstring, 선택적용 중 발생한 오류

보고를 받으면 서버가 곧바로 재평가해요.
그래서 Agent가 처음 접속했을 때 기준선을 맞추는 용도로도 쓸 수 있어요.

update job의 deploy 파라미터

OTA 업데이트가 발생하면 Agent는 기존 SSE deploy 이벤트를 받아요.
params는 다음과 같아요.

{ "artifact": { "__type": "FileRef", "id": "...", "downloadUrl": "https://..." }, "release_id": "...", "version": "1.2.0", "channel": "stable", "sequence": 2, "forced": true, "checksum_sha256": "..." }
필드타입설명
artifactobject내려받을 아티팩트 참조. downloadUrl은 전송할 때마다 새로 주입돼요
release_idstring적용할 릴리스
versionstring릴리스 버전 라벨
channelstring릴리스 채널
sequenceint릴리스 순서 값
forcedboolean강제 업데이트 여부. 판단은 서버가 하고, 집행(앱 차단 등)은 Agent가 해요
checksum_sha256string다운로드 후 무결성 검증용 체크섬

forced 여부와 무관하게, 아티팩트를 받아 어떻게 적용할지는 여러분의 로컬 워크플로우가 결정해요.
checksum_sha256으로 내려받은 파일을 검증한 뒤 적용해주세요.

에러 응답

{ "statusCode": 429, "code": "rate_limited", "message": "Rate limit exceeded", "retryAfter": 42 }
HTTP상황
401토큰 없음/무효
403권한 부족 (스코프 불일치 등)
404리소스 없음
409중복 (idempotency 충돌 등)
422입력 검증 실패
429레이트 리밋 초과
500서버 에러

리밋·큐로 거부되어 Job 자체가 rejected가 되는 경우는 제한과 정책에서 다뤄요.
토큰 접근 범위 조회 엔드포인트의 429는 본문 형태가 달라요(scope: "token_read").

사용 흐름 예시 — Sync 모드 Webhook

외부 API Token으로 결과까지 한 번에 받는 가장 단순한 패턴이에요.
responseMode: sync로 만들어 둔 트리거를 호출하면 워크플로우 완료까지 기다린 응답이 그대로 와요.

TRIGGER_ID="t-xxxxxxxx" # 대시보드 → Triggers → 상세에서 복사 TOKEN="dpl_..." # 대시보드 → API Tokens → 발급 모달의 평문 1회 노출값 RESP=$(curl -fsS -X POST https://api.deplite.io/v1/triggers/$TRIGGER_ID/run \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"ref": "main", "params": {"replicas": "3"}}') echo "$RESP" | jq '{ jobId, status, exitCode, output, timedOut }'

응답 예:

{ "jobId": "j-abc-1234", "status": "success", "exitCode": 0, "output": { "deployedRef": "main-7f3a9b", "url": "https://app.example.com" } }

responseTimeoutMs를 넘기면 "timedOut": true가 붙어요.
이 경우 워크플로우는 계속 실행되지만, 결과를 외부에서 받으려면 트리거의 notify… 옵션으로 Slack/Discord 알림을 받거나 대시보드 Jobs 화면에서 확인해야 해요.

비동기(responseMode: async) 트리거를 쓰는 경우는 응답의 jobId로 식별만 가능하고, 결과 전달은 마찬가지로 notify 또는 대시보드에서 확인하는 흐름이에요.

관련 문서

최종 수정 일자: