API 사용

CastLine 의 스트림·공유 링크·외부 송출은 /api/v1 REST API 로도 다룰 수 있습니다. 요청·응답은 JSON 이고 필드 이름은 camelCase 입니다.

API 키 인증

  1. 콘솔 관리 → API 키(/console/api-keys)에서 소유자가 키를 발급합니다. 키 역할은 manager(스트림·링크·송출 생성·수정·켜기·끄기) 또는 viewer(조회만) 중에서 고릅니다.
  2. 키(ck_…)는 발급할 때 한 번만 보입니다. 잃어버리면 폐기하고 새로 발급하세요.
  3. 모든 요청에 Authorization 헤더를 붙입니다.
인증 헤더
Authorization: Bearer ck_…
스트림 목록
curl -H "Authorization: Bearer ck_…" "https://castline.dotoritos.net/api/v1/streams?limit=20"
스트림 켜기
curl -X POST -H "Authorization: Bearer ck_…" "https://castline.dotoritos.net/api/v1/streams/<streamId>/on"
  • 키는 자기 고객사 자원만 다룹니다. 다른 고객사 자원은 404 NOT_FOUND 입니다.
  • 등급의 API 키 한도가 0 이면 키를 발급할 수 없습니다(403 FEATURE_NOT_ALLOWED).
  • 비밀번호 변경·로그인 세션 관리·탈퇴·콘솔 미리보기처럼 사람 계정이 필요한 작업은 API 키로 할 수 없습니다.
  • 해지된 고객사의 키는 410 CUSTOMER_TERMINATED, 정지된 고객사의 변경 요청은 423 CUSTOMER_SUSPENDED 를 받습니다.

예약 켜기·끄기 (cron)

영업시간에만 송출하려면 서버의 스케줄러(cron 등)가 manager 역할 키로 일괄 켜기·끄기를 부르게 합니다(한 번에 최대 50개).

일괄 켜기 (최대 50개)
curl -X POST -H "Authorization: Bearer ck_…" -H "Content-Type: application/json" -d '{"ids":["<streamId>"],"action":"on"}' "https://castline.dotoritos.net/api/v1/streams/bulk"
예약 켜기·끄기 (crontab -e, 서버 시간대 KST 기준)
# manager 역할 API 키로 평일 09:00 켜기, 18:00 끄기
CASTLINE_KEY=ck_…
0 9 * * 1-5  curl -fsS -X POST -H "Authorization: Bearer $CASTLINE_KEY" -H "Content-Type: application/json" -d '{"ids":["<streamId>"],"action":"on"}' https://castline.dotoritos.net/api/v1/streams/bulk
0 18 * * 1-5 curl -fsS -X POST -H "Authorization: Bearer $CASTLINE_KEY" -H "Content-Type: application/json" -d '{"ids":["<streamId>"],"action":"off"}' https://castline.dotoritos.net/api/v1/streams/bulk

일괄 요청은 항목별 결과를 207 Multi-Status 로 돌려줍니다. 일부만 실패할 수 있으니 ok 가 false 인 항목의 error.code 를 확인하세요.

일괄 요청 결과 (207 Multi-Status, 항목별 성공·실패)
{
  "data": {
    "results": [
      { "id": "<streamId>", "ok": true },
      { "id": "<streamId2>", "ok": false, "error": { "code": "RESOURCE_LOCKED", "message": "관리자가 잠근 자원입니다." } }
    ]
  }
}

응답과 오류 형식

성공하면 {"data": …, "meta": {…}} 를, 실패하면 아래 형식을 돌려줍니다. message 는 사람이 읽는 한국어 문구이고, 프로그램은 code 로만 분기하세요. 모든 응답에는 X-CastLine-Request-Id 헤더가 있으며, 문의할 때 이 값(requestId)을 알려 주면 빠르게 찾을 수 있습니다.

오류 응답 형식
{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "동시 활성 스트림 한도(5개)를 초과했습니다.",
    "details": { "limitKey": "max_active_streams", "limit": 5, "current": 5, "requested": 1 },
    "requestId": "req_…"
  }
}
  • 수정 가능한 자원은 version 을 돌려줍니다. PATCH 에 If-Match: <version> 을 보내면 그 사이 다른 사람이 바꿨을 때 409 VERSION_CONFLICT 로 알려 줍니다.
  • 목록의 알 수 없는 쿼리 파라미터와 본문 필드는 422 VALIDATION_FAILED(rule=unknown_field) 입니다.

오류 코드

codeHTTP의미 / details
VALIDATION_FAILED422입력 검증 실패. details.fields: [{field, rule, message}]. 초대·재설정 토큰을 제출했는데 쓸 수 없으면 details.reason
INVALID_SOURCE_URL422원본·목적지 URL 오류. details.reason: SCHEME_NOT_ALLOWED, HTTP_SOURCE_NOT_HLS, PRIVATE_ADDRESS, SELF_ADDRESS, DNS_FAILED, MALFORMED
UNAUTHENTICATED401세션·API 키 없음 또는 만료
INVALID_CREDENTIALS401이메일·비밀번호 불일치
ACCOUNT_LOCKED423로그인 잠금. details.lockedUntil
ACCOUNT_DISABLED403비활성 사용자, 또는 해지된 고객사 멤버의 로그인
FORBIDDEN403역할 권한 없음. details.action (권한 행 ID)
CSRF_FAILED403Origin 불일치 (쿠키 인증 변경 요청)
NOT_FOUND404없음, 또는 다른 고객사의 자원
CONFLICT409유일성 위반(이름 등). details.field
VERSION_CONFLICT409낙관적 잠금 실패(If-Match). details.currentVersion
LAST_OWNER409마지막 소유자는 제거·강등·비활성화·탈퇴할 수 없음
LAST_SUPER_ADMIN409마지막 최고 관리자 보호 (스태프 전용)
SELF_ACTION_FORBIDDEN409자기 계정 비활성화·강등·삭제 (스태프 전용)
TIER_IN_USE409고객이 배정된 등급 삭제 (스태프 전용). details.customerCount
QUOTA_EXCEEDED403개수 한도 초과. details: {limitKey, limit, current, requested}
PROTOCOL_NOT_ALLOWED403등급이 허용하지 않는 프로토콜. details: {limitKey, protocol, allowed}
FEATURE_NOT_ALLOWED403등급이 허용하지 않는 기능(임베드, 비밀번호 링크, on-demand, API 키). details.limitKey
PLATFORM_CAPACITY503플랫폼 전체 수용량 도달 — 잠시 뒤 다시 시도
CUSTOMER_SUSPENDED423정지된 고객사의 변경 요청
CUSTOMER_TERMINATED410해지된 고객사의 API 키 요청
RESOURCE_LOCKED423관리자가 잠근 스트림·송출. details: {reason, lockedResource}
LINK_NOT_FOUND404공개 API: 무효·폐기 토큰
LINK_EXPIRED410공개 API: 만료된 링크
LINK_DISABLED403공개 API: 비활성·한도정지 링크
LINK_PASSWORD_REQUIRED401공개 API: 링크 비밀번호 필요
LINK_PASSWORD_INVALID401공개 API: 링크 비밀번호 불일치
LINK_PASSWORD_LOCKED429공개 API: 비밀번호 실패가 많아 일시 거절. Retry-After, details.until
MAIL_UNAVAILABLE503메일 발송이 설정되지 않아 처리할 수 없음 (비밀번호 재설정 등)
EMBED_NOT_ALLOWED403임베드 비허용 또는 허용 도메인 불일치
VIEWER_KICKED403공개 API: 강제 종료된 시청자의 재접속 차단 중. details.until
STREAM_NOT_LIVE409미리보기·티켓 요청 시 스트림이 꺼져 있음
MEDIA_SERVER_UNAVAILABLE503미디어 서버에 연결할 수 없음 (상태 조회 계열)
RATE_LIMITED429속도 제한 초과. Retry-After 헤더(초) 뒤 다시 시도
INTERNAL_ERROR500서버 오류. 문의 시 requestId 를 알려 주세요

속도 제한

한도를 넘으면 429 RATE_LIMITED 와 Retry-After 헤더(초)를 받습니다. 그 시간만큼 기다린 뒤 다시 시도하세요. 같은 스트림의 “다시 연결”(POST /streams/{id}/resync)은 30초에 한 번입니다.

대상한도
API 키 요청API 키당 300회 / 1분
로그인한 사용자(웹 화면) 요청사용자당 600회 / 1분
고객 자료 내보내기사용자당 10회 / 1시간
공개 재생 티켓IP당 30회 / 1분
로그인 시도IP당 10회 / 1분
비밀번호 재설정 메일 요청IP당 5회 / 1분
초대·재설정 토큰 제출IP당 20회 / 1분

페이지네이션과 정렬

목록은 커서 방식입니다. limit 은 기본 20, 최대 100 이고, 응답의 meta.nextCursor 를 다음 요청의 cursor 로 넘깁니다. nextCursor 가 null 이면 마지막 페이지입니다. 커서는 그 목록 전용이라 다른 목록이나 조건에 쓰면 422(rule=invalid_cursor)입니다.

다음 페이지
curl -H "Authorization: Bearer ck_…" "https://castline.dotoritos.net/api/v1/streams?limit=50&cursor=<meta.nextCursor>"

정렬은 sort=<필드>:asc 또는 sort=<필드>:desc 로 지정합니다(예: sort=name:asc). 목록마다 정렬할 수 있는 필드가 정해져 있고, 그 밖의 값은 422 입니다.