인증
Sursa API로 보내는 모든 요청은 Authorization 헤더에 API 키나 애플리케이션의 OAuth 액세스 토큰을 담아요.
Authorization: Bearer kb_3f9c…
키는 조직을 식별하고, 요청이 무엇을 보고 바꿀 수 있는지를 키의 역할, 스코프, 데이터 프로필, 컬렉션으로 정해요. API 전용 주소에는 세션이나 쿠키가 없어요. 요청마다 따로 인증하므로 같은 키로 여러 요청을 동시에, 여러 서버에서 보낼 수 있어요.
curl https://api.sursa.com/v1/me \
-H "Authorization: Bearer $SURSA_API_KEY"이전 연동에서는 키를 X-API-Key 헤더로 보내기도 해요. 이 방식도 여전히 받지만, 새 코드에서는
Authorization: Bearer를 사용하세요.
자격 증명의 종류
| 자격 증명 | 형태 | 사용할 수 있는 곳 |
|---|---|---|
| 조직 API 키 | kb_… | 역할, 스코프, 데이터 프로필, 컬렉션의 범위 안에서 API의 모든 엔드포인트. |
| 사용자 지정 소스 키 | kbsrc_… | 해당 사용자 지정 소스의 푸시 엔드포인트(/v1/push/sources/{source_id}/…)만. |
| OAuth 액세스 토큰 | kbat_… | 토큰의 스코프 범위 안에서 API 레퍼런스의 엔드포인트. 인가 코드로 POST /oauth/token에서 받은 토큰은 동의한 직원을 대신해 동작하고, client_credentials 토큰은 API 키처럼 조직을 대신해 동작해요. 유효 기간은 1시간이에요. |
모두 같은 방식으로 보내요. 사용자 지정 소스 키로는 그 소스 밖의 어떤 것도 읽거나, 검색하거나, 바꿀 수 없어요. 연동 플랫폼처럼 외부 서비스가 키를 보관하는 곳에는 이 키를 사용하세요.
인증 오류
| 상태와 코드 | 의미 | 조치 |
|---|---|---|
401 auth.not_authenticated | 키가 없거나, 잘못 입력되었거나, 폐기되었어요. | 헤더와 키 값을 확인하세요. |
401 api_keys.expired | 키의 만료일이 지났어요. | 새 키를 만들어 이전 키를 교체하세요. |
401 sources.push_key_invalid | 사용자 지정 소스 키가 잘못되었거나, 폐기되었거나, 다른 소스의 키예요. | 키와 경로의 소스 ID를 확인하세요. |
401 oauth.token_expired | OAuth 액세스 토큰이 만료되었어요. | 리프레시 토큰으로 새 토큰을 받으세요. |
403 api_keys.scope | 키에 이 오퍼레이션에 필요한 스코프가 없어요. | 스코프를 추가하거나 그 스코프가 있는 키를 사용하세요. |
403 api_keys.feature_disabled | 조직의 요금제에 API 키가 포함되어 있지 않아요. | 조직 관리자에게 문의하세요. |
403 api_keys.ip_not_allowed | 키에 허용된 주소 밖에서 보낸 요청이에요. | 허용된 네트워크에서 호출하거나 키의 허용 주소를 바꾸세요. |
403 api_keys.mcp_only | 개인 MCP 키를 /mcp 엔드포인트 밖에서 사용했어요. | API에는 조직 API 키를 사용하세요. |
403 oauth.operation_not_allowed | 공개 API에 속하지 않는 오퍼레이션이라 OAuth 토큰으로는 호출할 수 없어요. | API 레퍼런스에 있는 오퍼레이션을 사용하세요. |
403 org.suspended | 조직이 일시 정지되었어요. 데이터는 보존돼요. | 조직 관리자에게 문의하세요. |
403은 요청이 인증되었지만 허용되지 않았다는 뜻이에요. 키가 볼 수 없는 객체에는 존재하지 않는 객체와 똑같이 404로
응답하므로, 키로는 접근 범위 밖에 무엇이 있는지 알 수 없어요.
데이터 프로필로 요청하기
admin 역할의 키로는 다른 사용자 그룹에게 무엇이 보이는지 확인할 수 있어요. X-View-As 헤더를 보내면 요청이 지정한
데이터 프로필과, 필요하면 역할까지 적용해 실행돼요.
curl "https://api.sursa.com/v1/cards?limit=20" \
-H "Authorization: Bearer $SURSA_ADMIN_KEY" \
-H "X-View-As: employee:viewer"이 모드의 요청은 읽기만 해요. 무언가를 바꾸는 요청은 403 상태와
view_as.read_only 코드를 반환해요. OAuth 토큰이나 admin 역할이 없는 키로는
X-View-As 헤더를 쓸 수 없어요. 이때는 403 상태와 view_as.admin_key_required
코드로 응답해요. 존재하지 않는 프로필을 지정한 헤더에는 400 상태와
view_as.invalid_header 코드로 응답해요.
브라우저 애플리케이션
API는 모든 웹 오리진의 요청을 허용하고(Access-Control-Allow-Origin: *) 쿠키를 전혀 쓰지 않으므로, 웹 페이지에서
fetch로 호출할 수 있어요. 이때 키는 페이지 안에 있어서 페이지를 쓰는 누구에게나 보여요. 공개 컬렉션으로 제한한
viewer 키처럼 그 사용자들에게 보여도 괜찮은 키로만 브라우저에서 API를 호출하거나, 브라우저와 Sursa 사이에 직접
운영하는 서버를 두세요.
직원만 할 수 있는 일
조직 API 키는 사람이 아니라 조직을 대신해 동작해요. API의 두 부분은 사람에게 속하므로, 직원을 대신해 동작하는 토큰으로만 사용할 수 있어요. 그런 토큰은 Sursa 세션이나 직원의 동의를 받아 발급한 OAuth 액세스 토큰이에요.
대화는 사람에게 속해요. 조직 API 키는
GET /v1/conversations에서 그 키가 직접 시작한 대화만 볼 수 있어요.
공개 API에는 대화를 시작하는 오퍼레이션이 없으므로 키에서 보는 목록은 보통 비어 있고, 직원의 대화는 키에 절대 보이지
않아요. 대화 없이 하는 질문, 즉 POST /v1/ask나
POST /v1/chat은 ask 스코프가 있는 모든 키로 보낼 수 있어요. 직원의 대화 목록을 조회하고
GET /v1/conversations/{conv_id}로 한 대화의 기록을 읽으려면 그 직원을
대신하는 OAuth 토큰으로 API를 호출하세요. 이 토큰에는 그 직원 자신의 대화만 보여요. 다른 대화에는 404 상태와
conversations.not_found 코드로 응답해요.
카드 검증은 직원만 할 수 있어요. 검증은 사람이 내용을 직접 확인했다는 표시이므로
POST /v1/cards/{card_id}/verification/verify와
POST /v1/cards/{card_id}/verify에는 세션이나, 그 카드를 검증할 수 있는 직원을 대신하는
OAuth 토큰이 필요해요. 조직 API 키나 client_credentials 토큰으로 호출하면 400 상태와
cards.verify_user_account_required 코드로 응답해요. 일반적인 확인이
먼저 이루어져요. 키가 볼 수 없는 카드에는 404로, 그 카드를 검증할 권한이 없는 키에는 403으로 응답해요.