API 개요
모든 RolChat REST 엔드포인트는 하나의 규약을 따릅니다. 같은 기본 URL, 같은 응답 봉투, 같은 페이지네이션, 같은 오류 형태입니다. 한 번만 익히면 엔드포인트 레퍼런스의 모든 엔드포인트 그룹을 같은 방식으로 읽을 수 있습니다.
기본 URL과 버전 관리
섹션 제목: “기본 URL과 버전 관리”https://api.rolchat.com/api/v1/버전은 경로에 들어 있습니다. 선택적 필드, 새 엔드포인트, 기본값이 있는 새 쿼리 매개변수를 추가하는 것은 호환성을 깨는 변경이 아니며 버전을 올리지 않습니다. 호환성을 깨는 변경은 v2로 출시되며, 지원 중단된 v1 엔드포인트는 공지 후 최소 6개월 동안 계속 작동합니다(지원 중단 참고).
| 방식 | 헤더 | 용도 |
|---|---|---|
| JWT 베어러 | Authorization: Bearer <access_token> |
대화형 세션(웹 앱, 모바일 앱) |
| API 키 | Authorization: Bearer rcp_<secret> |
머신 간 호출, 플러그인 API 키 |
| HMAC 서명 | X-RolChat-Signature: sha256=… |
자체 시스템에서 들어오는 웹훅. 웹훅 참고 |
| 없음 | - | 공개 위젯 엔드포인트(/widget/…, /forms/…). 사이트와 출처로 범위가 제한됩니다 |
연동에는 API 키(개인 액세스 토큰)를 사용하세요. 키는 설정 → 플러그인 → RolChat API 키에서 만들며, 한 번만 표시되고 해시로만 저장됩니다. 키는 그것을 만든 멤버보다 많은 일을 할 수 없습니다. 호출할 때마다 키의 범위가 그 멤버의 현재 권한과 대조됩니다. JWT 수명, X-Account-Id 헤더, 여러 회사에 걸친 세션은 인증을 참고하세요.
응답 봉투
섹션 제목: “응답 봉투”단일 리소스:
{ "data": { "id": "cnt_01HK…", "email": "ada@example.com" }, "meta": { "request_id": "req_01HK…" }}목록:
{ "data": [ { … }, { … } ], "meta": { "request_id": "req_01HK…", "count": 50, "next_cursor": "cur_01HK…", "prev_cursor": "cur_01HK…", "has_more": true }}본문이 없는 응답(삭제 후의 204 No Content)에도 X-Request-Id 헤더가 포함됩니다.
오류:
{ "errors": [ { "code": "validation_failed", "message": "Email must be valid.", "field": "email", "details": { "received": "not-an-email" } } ], "meta": { "request_id": "req_01HK…" }}code는 기계가 읽을 수 있는 snake_case 값이며 분기 처리에 쓰는 값입니다. message는 영어이며 로그용입니다. field와 details는 도움이 될 때 포함되며 개인 데이터를 절대 담지 않습니다. API는 errors 배열과 함께 200을 반환하지 않습니다. 오류가 있으면 상태는 400 이상입니다. 전체 코드 목록은 오류 페이지에 있습니다.
페이지네이션
섹션 제목: “페이지네이션”항목이 늘어날 수 있는 목록 엔드포인트는 커서 페이지네이션을 사용합니다. 첫 페이지는 커서 없이 요청하고, 이후에는 받은 next_cursor를 그대로 다시 전달합니다.
GET /api/v1/contacts?limit=50GET /api/v1/contacts?limit=50&cursor=eyJrIjoi…limit의 기본값은 50이고 최대 200입니다. 더 큰 값은400 validation_failed로 거부됩니다.- 커서는 불투명한 값이며 24시간 후 만료됩니다(
code: cursor_expired가 포함된400 validation_failed). - 결과는 첫 페이지에서 찍은 스냅샷을 기준으로 일관됩니다. 페이지 사이에 삭제된 레코드는 사라지고, 새 레코드는 커서 없이 처음부터 다시 시작할 때만 나타납니다.
- 이를 선호하는 클라이언트를 위해
rel="next"와rel="prev"가 있는Link헤더도 보냅니다.
멱등성
섹션 제목: “멱등성”POST, PATCH, DELETE 요청에는 Idempotency-Key 헤더(UUID 또는 ULID, 최대 255자)를 함께 보내세요.
- 키가 있는 첫 요청은 실행되며, 그 상태와 본문이 24시간 동안 저장됩니다.
- 같은 키와 같은 본문으로 반복하면 부수 효과를 다시 실행하지 않고 저장된 응답을 반환합니다.
- 같은 키에 다른 본문으로 반복하면
409 idempotency_key_conflict로 거부됩니다.
부수 효과가 있는 생성 작업을 하는 모든 호출에 사용하세요: 메시지, 이메일, SMS 보내기, 전화 걸기, 요금이 부과되는 모든 작업. GET 요청은 항상 멱등이며 이 헤더를 무시합니다.
속도 제한
섹션 제목: “속도 제한”제한은 분 단위로 집계되며 계정, API 키 또는 사용자를 기준으로 적용됩니다(로그인이 필요 없는 경로에서는 IP 주소 기준). 기본 상한:
| 구분 | 기본 한도 | 분당 |
|---|---|---|
| 로그인하지 않은 요청(IP별) | 60 | IP당 |
| 로그인한 사용자(대시보드) | 1 000 | 사용자당 |
| API 키 | 1 000 | 키당 |
| 공개 위젯 엔드포인트 | 방문자당 60, 네트워크 주소당 600 | 분당 |
로그인(/auth/login) |
5 | IP당 |
| 수신 웹훅 | 300 | 분당 |
| MCP 서버 | 600 | 분당 |
| OAuth 엔드포인트 | 600 | 분당 |
이 상한은 플랫폼 기본값이며 운영자가 변경할 수 있습니다. 플랜에 따라 배수로 늘어나지 않으며, 엔터프라이즈 한도는 계약으로 정합니다. 속도 제한이 있는 엔드포인트는 다음을 반환합니다.
X-RateLimit-Limit: 1000X-RateLimit-Remaining: 543한도를 넘으면 응답은 errors 배열에 code: rate_limited가 포함된 429이며, 초 단위의 Retry-After 헤더가 함께 옵니다. 다음 호출 전에 그 시간만큼 기다리세요. 로그인에 열 번 실패하면 계정이 30분 동안 잠깁니다.
크기와 시간 제한
섹션 제목: “크기와 시간 제한”| 범주 | 최대 요청 본문 | 서버 시간 제한 |
|---|---|---|
| 기본 | 1 MB | 30초 |
| 첨부파일이 있는 메시지 | 25 MB | 30초 |
| CSV 가져오기 | 50 MB | 202를 반환하고 백그라운드에서 실행 |
| 지식 베이스 이미지 | 10 MB | 30초 |
| 일괄 API | 10 MB | 30초 |
| 검색 | 1 MB | 10초 |
| AI 요청 | 1 MB | 60초 |
| 위젯 엔드포인트 | 100 KB | 30초 |
크기를 초과한 본문에는 413 payload_too_large가 반환됩니다. 업스트림이 시간 초과되면 code: upstream_timeout이 포함된 504가 반환되며, 재시도가 도움이 될 때는 retry_after 힌트가 함께 옵니다.
콘텐츠 유형, 날짜, ID
섹션 제목: “콘텐츠 유형, 날짜, ID”- 요청과 응답은
application/json; charset=utf-8입니다. 파일 업로드는multipart/form-data를 사용하고, CSV 내보내기는text/csv를 반환합니다. 잘못된 UTF-8은400 validation_failed로 거부됩니다. - 타임스탬프는 밀리초 정밀도의 UTC ISO-8601 형식입니다:
2026-04-20T14:23:45.123Z. 입력 시에는 어떤 ISO-8601 오프셋이든 받아 UTC로 정규화합니다. - 식별자는 불투명한 ULID 또는 UUID입니다. 숫자 ID는 없으며, 이메일 주소나 전화번호는 URL에 절대 나타나지 않습니다.
테넌트 격리와 권한
섹션 제목: “테넌트 격리와 권한”인증된 모든 요청은 하나의 계정 안에서 실행됩니다. 다른 계정에 속한 리소스나 호출자의 역할이 다루지 않는 사이트의 리소스에는 403 대신 404 not_found가 반환되므로, 레코드의 존재 여부가 절대 드러나지 않습니다. 필요한 권한(예: contacts.delete)이 없는 유효한 토큰에는 403 forbidden이 반환됩니다. 일부 권한에는 목록이 반환하는 범위를 좁히는 범위 접미사(conversations.read:own, :team, :all)가 붙습니다.
PATCH는 쓰기 가능한 필드만 받습니다. id, account_id, created_at, updated_at과 resolved_at 같은 상태 필드는 읽기 전용이며, 이를 보내면 details.forbidden_fields가 포함된 400 validation_failed가 반환됩니다. 상태 변경은 POST /tickets/:id/resolve 같은 전용 작업으로 합니다.
모든 쓰기 작업은 계정 감사 로그에 기록됩니다.
관측성 헤더
섹션 제목: “관측성 헤더”모든 응답에는 다음이 포함됩니다.
X-Request-Id: req_01HK…X-Request-Id를 기록해 두세요. 지원팀이 가장 먼저 묻는 값입니다.
CORS
섹션 제목: “CORS”브라우저 대시보드의 출처는 https://app.rolchat.com입니다. 공개 위젯 엔드포인트는 모든 출처 또는 사이트에서 인증한 출처만 허용합니다. API 키를 사용한 서버 간 호출에는 CORS가 적용되지 않습니다.
지원 중단
섹션 제목: “지원 중단”- 변경은 변경 로그에 공지되며, 해당 엔드포인트는
Deprecation: true와 제거 날짜가 담긴Sunset헤더를 보내기 시작합니다. - 공개 엔드포인트는 공지 후 최소 6개월 동안 계속 작동합니다.
- 제거는 새 메이저 버전에서만 이루어집니다.
v1안에서의 변경은 추가만 합니다.
상태 확인
섹션 제목: “상태 확인”모든 서비스는 /healthz(활성 상태)와 /readyz(준비 상태)를 제공합니다.