개발자

공개 API Beta

안전한 범위 지정 API 키와 안정적인 버전 관리형 JSON 규격으로 워크스페이스 통합을 만드세요.

인터랙티브 API 레퍼런스 열기

빠른 시작

  1. 01

    API 키 열기

    설정을 열고 개발자를 선택한 뒤 API 키에서 키 만들기를 선택하세요. 소유자와 관리자가 키를 만들 수 있어요.

  2. 02

    API 키 만들기

    이름을 입력하고, 만료 기간(일)을 고르고, 채널 접근 권한을 모든 채널 또는 선택한 채널로 정하고, 범위에서 통합에 필요한 최소한의 범위를 고르세요. 요청은 키에 엔드포인트가 요구하는 정확한 리소스 작업 권한이 있을 때만 성공해요. 키 만들기를 선택하세요.

  3. 03

    API 키 저장

    전체 키는 한 번만 표시돼요. 시크릿 관리자에 복사한 뒤 저장했어요를 선택하세요.

  4. 04

    키 보내기

    Bearer 토큰을 쓰거나 같은 값을 x-api-key로 보내세요. 키를 쿼리 문자열이나 브라우저 코드에 넣지 마세요.

cURL

curl https://www.usesonny.com/api/v1/contacts?limit=25 \
  --header "Authorization: Bearer sonny_your_key"

키는 안전하게 보관돼요

키 보안
키는 sonny_ 접두사와 무작위 문자 64개로 이루어지고, 저장 시 단방향 해시 처리되며, 만료 기간을 설정할 수 있고, 키당 분당 600회 요청 제한이 있어요. 키는 하나의 워크스페이스에 묶여요.
키를 취소하려면 옆의 휴지통 버튼을 선택하세요. API 키를 취소할까요?에서 삭제를 선택해 확인하세요. 키가 즉시 중지돼요.
모든 호출에서 권한 확인
Sonny는 해시와 범위를 확인한 뒤, 키를 만든 사람의 활성 워크스페이스 멤버십, 역할, 결제 상태를 다시 확인해요. 그 사용자를 제거하거나 비활성화하면 키도 즉시 비활성화돼요.
선택한 채널은 모든 REST API와 MCP 호출에 적용돼요. 연락처, 속성, 태그, 웹훅 관리 엔드포인트는 모든 채널 접근 권한이 필요해요. 양식으로 만들기는 선택한 채널에서 contacts:write와 conversations:write로 할 수 있고, 독립 연락처 엔드포인트는 계속 워크스페이스 전체 범위예요.

범위

  • contacts:read
  • contacts:write
  • tags:read
  • tags:write
  • conversations:read
  • conversations:write
  • messages:read
  • messages:write
  • messages:send
  • webhooks:read
  • webhooks:write
  • kb:read
  • kb:write
  • csat:read
  • attachments:write
  • members:read
  • contact-memory:read
  • contact-memory:write
  • reporting:read

리소스

연락처
연락처, 유형이 지정된 속성, 정확한 값 필터, 고객 메모리를 관리해요. 연락처를 보관하거나, 데이터 보호 요청에 따라 모든 대화와 함께 영구 삭제할 수 있어요.
소스
구성된 소스와 각 소스가 채팅, 이메일 또는 둘 다를 지원하는지 확인해요.
대화
양식에서 문의를 만들고, 확인이 필요한 대화를 필터링하고, 상담원이나 팀에 배정하고, 다시 알림, 태그, 일괄 업데이트를 해요.
동기화
저장된 커서로 워크스페이스의 지속적인 변경 사항과 삭제 기록을 재생해요.
멤버와 팀
배정 가능한 팀원, 응대 가능 상태, 실제 채널 접근 권한을 확인해요.
리포트
고객 지원, 팀, AI, 지식, 리드, 응대 가능 시간 리포트를 읽어요.
메시지
메시지 기록과 첨부 파일 추출 결과를 읽고, 비공개 파일을 업로드하고, 내부 메모를 추가하고, 고객 답장을 보내거나 수정해요.
웹훅
엔드포인트, 구독, 테스트, 전송, 재시도를 관리해요.
지식 베이스
소스별 도움말 센터 아티클과 카테고리를 만들고, 읽고, 업데이트하고, 삭제해요.
고객 만족도
워크스페이스, 채널, 대화별 CSAT 점수를 읽고, 평가 값, 의견, 담당자, 기간으로 필터링한 개별 평가 목록을 가져와요.

AI 도구에서 Sonny 사용하기

Sonny MCP는 모든 공개 API 작업을 도구로 제공해요. 클라이언트는 OAuth 2.1 로그인이나 범위 지정 API 키로 연결하며, 모든 호출에 같은 범위, 워크스페이스 경계, 비즈니스 규칙이 적용돼요.

Sonny MCP 가이드 읽기

응답과 오류

컬렉션 응답은 data를 쓰고, 해당하는 경우 페이지 정보를 포함해요. 모든 응답에는 x-request-id가 있어요. 안전한 요청 ID를 직접 보내면 Sonny가 그대로 돌려줘요. 오류는 민감한 구현 세부 정보를 드러내지 않는 안전한 메시지를 반환해요.

{
  "error": {
    "type": "validation_error",
    "message": "Invalid email address",
    "requestId": "req_01J..."
  }
}
400
입력값, JSON, 쿼리 또는 커서가 올바르지 않아요.
401
API 키가 없거나, 올바르지 않거나, 만료됐거나, 범위가 없어요.
402
워크스페이스 결제 상태 때문에 이 요청이 차단됐어요.
403
키를 만든 사람의 워크스페이스 역할로는 허용되지 않아요.
404
키의 워크스페이스에 해당 리소스가 없어요.
409
요청이 기존 리소스와 충돌해요.
410
동기화 커서가 만료됐어요. 현재 상태를 다시 불러오고 새 커서로 재생하세요.
413
업로드가 허용 크기를 넘었어요.
422
소스에 이메일 채널이 없거나 제출된 필드 값이 올바르지 않아요.
429
키당 요청 한도를 초과했어요.
500
예기치 않은 오류가 발생했어요. 요청 ID와 함께 다시 시도하세요.
503
웹훅 전송 적체가 포화 상태예요. 나중에 다시 시도하세요.

요청 한도

API 키마다 분당 최대 600회 요청할 수 있어요. 모든 응답은 표준 RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset 헤더로 현재 구간을 알려 주므로, 클라이언트가 추측하지 않고 스스로 속도를 조절할 수 있어요. 한도를 넘으면 API가 Retry-After 헤더와 함께 429를 반환해요. 그 초만큼 기다린 뒤 다시 시도하세요.

버전 관리와 지원 중단

API 버전은 URL 경로(/api/v1)에 들어가요. 한 버전 안에서는 새 엔드포인트, 새 선택 필드, 새 열거형 값처럼 추가하는 변경만 해요. 호환되지 않는 변경은 새 버전으로 출시하며, v1 엔드포인트를 종료하기 전에는 최소 6개월 전에 이 페이지, 활성 API 키가 있는 워크스페이스 소유자에게 보내는 이메일, 영향받는 엔드포인트의 Deprecation 및 Sunset 헤더로 알려 드려요.

보낸 답장 수정하기

  1. API 키나 MCP 연결에 messages:read와 messages:send 범위, 그리고 답장한 채널에 대한 접근 권한을 주세요.
  2. 대화의 메시지를 읽고 내가 보낸 사람의 답장 ID를 복사하세요. API 키는 키를 만든 사람으로, OAuth는 연결된 팀원으로 동작해요.
  3. 아래 요청으로 바꿀 텍스트를 보내거나, MCP에서 conversationId, messageId, body와 함께 edit_message를 호출하세요.
  4. 반환된 메시지를 확인하세요. ID, 첨부 파일, 읽음 확인, 원래 보낸 시간은 그대로예요.
curl --request PATCH \
  https://www.usesonny.com/api/v1/conversations/conversation_1/messages/message_1 \
  --header "Authorization: Bearer sonny_your_key" \
  --header "Content-Type: application/json" \
  --data '{"body":"The corrected reply"}'

수정하면 대화 기록과 연결된 채팅 클라이언트가 바로잡혀요. 이메일이나 알림을 다시 보내지 않으며, 이미 전달된 이메일은 바뀌지 않아요. 내가 고객에게 보낸 사람의 답장만 수정할 수 있고, 수신 메시지, 봇 답변, 내부 메모, 다른 팀원의 답장은 수정할 수 없어요. 대기 중인 이메일 전송이 끝난 뒤에 수정하세요. 바꿀 텍스트는 1–50,000자여야 하며, 이전 HTML과 링크 미리보기는 지워져요. 통합에는 message.updated 웹훅과 동기화 이벤트가 전달돼요. 더 새로운 메시지 ID만 폴링하면 수정을 찾을 수 없으니 안정적인 동기화 피드를 쓰세요.

양식으로 대화 만들기

양식 제출 내용을 POST /api/v1/conversations로 보내세요. Sonny가 이메일로 연락처를 찾거나 만들고, 답변을 저장하고, 선택한 소스의 이메일 채널에서 수신 대화를 열어요. 채널의 팀, 배정 규칙, 알림이 적용돼요. 상담원은 이메일로 답장해요.

  1. conversations:write와 contacts:write로 키를 만드세요. 클라이언트가 선택한 채널로 제한할 수 있어요. 소스 ID는 GET /api/v1/sources로 찾으며, 여기에는 conversations:read도 필요해요.
  2. n8n에서 HTTP Request 노드를 추가하세요. 메서드는 POST, URL은 https://www.usesonny.com/api/v1/conversations예요. 키는 Header Auth 자격 증명에 Authorization, 값 Bearer sonny_your_key로 저장하세요.
  3. Send Body를 켜고 JSON과 Using JSON을 고른 뒤, JSON 필드 전체를 Expression으로 바꾸고 이 예시를 붙여 넣으세요. 소스 ID를 바꾸고 입력 필드를 양식에 맞게 연결하세요. 재시도할 때 같은 값을 쓰도록 양식의 고정 고유 제출 ID를 사용하세요.
{{ {
  sourceId: "YOUR_CLIENT_SOURCE_ID",
  contact: { email: $json.email, name: $json.name },
  subject: "Website enquiry",
  message: $json.message,
  fields: {
    Company: String($json.company ?? ""),
    Budget: String($json.budget ?? ""),
    Service: String($json.service ?? "")
  },
  externalId: "website-form-" + $json.submissionId
} }}

더 많은 노드 옵션은 n8n HTTP Request 가이드를 참고하세요. 같은 기능의 MCP 도구는 create_conversation이며, 페이로드와 권한도 같아요.

새 필드 이름은 텍스트 속성이 돼요. 기존 숫자, URL, 날짜, 선택 필드에는 올바른 문자열 값을 보내야 하며, 잘못된 값이 있으면 해당 필드 이름과 함께 422를 반환하고 아무것도 저장하지 않아요. 날짜는 ISO 날짜나 타임스탬프를 받고, 선택 값은 옵션과 일치해야 해요. 필드는 최대 50개, 이름은 최대 100자, 값은 최대 5,000자까지 받아요. 속성은 연락처와 대화 사이드바에 표시돼요. 선택 항목인 htmlMessage를 보내더라도 두 메시지 본문 모두에 답변 사본이 남아요.

선택 항목인 tags에는 기존 워크스페이스 태그 ID를 최대 20개 넣을 수 있어요. 응답에는 conversation, contact 요약, message, deduplicated가 들어 있어요. 새 제출은 201을 반환해요. 같은 소스에서 externalId를 다시 쓰면 원래 ID와 deduplicated: true와 함께 200을 반환하고, 바뀐 내용은 무시돼요. 외부 ID가 없으면 호출할 때마다 새 대화가 만들어져요. 생성 시 첨부 파일과 AI 자동 응답은 지원하지 않아요.

에이전트 워크플로

분류하고, 처리하고, 동기화 상태 유지하기

REST와 MCP는 같은 권한과 워크플로를 공유해요. 자격 증명은 현재 채널 접근 권한을 좁힐 수만 있어요. 멤버십에서 채널을 빼면 통합에서도 그 채널이 빠져요.

확인이 필요한 대화 찾기

awaitingReply, unread, unassigned, assigneeId, agentGroupId, snoozed, priority, tagIds로 필터링하세요. 답장 대기는 내부 메모를 무시하고, 읽지 않음은 인증된 팀원 기준이에요. 미배정은 팀이 배정돼 있어도 개인 담당자가 없다는 뜻이에요. 태그는 전달한 ID 중 하나라도 일치하면 돼요.

GET /api/v1/conversations?status=open&awaitingReply=true&compact=true&sort=waitingSince&direction=asc

waitingSince, lastMessageAt, createdAt 또는 업무 우선순위로 정렬하고 방향은 asc나 desc로 정하세요. 값이 같으면 ID로 순서를 정해요. 필터를 생략하면 compact=false와 snoozed=any가 유지돼요. REST tagIds는 쉼표로 구분된 ID를 받고, MCP는 배열도 받아요. waitingSince는 마지막 답장 이후 첫 수신 메시지부터 시작하며, 후속 메시지나 내부 메모로 초기화되지 않아요. 웹훅이 오지 않을 때도 오래된 스레드가 다시 드러나도록 이 대기열 검사를 예약 실행하세요.

받은편지함을 다시 읽지 않고 따라잡기

conversations:read로 GET /api/v1/sync를 쓰세요. 안정적인 피드에는 대화 변경, 태그, 메시지, 연락처 속성, 메모리, 삭제 기록이 포함돼요. 페이로드마다 자체 읽기 범위도 필요해요. 메시지 본문에는 messages:read, 메모리에는 contact-memory:read가 필요해요. 제한된 자격 증명은 허용된 채널만 받아요.

  1. 커서 없이 시작해 hasMore가 false가 될 때까지 nextCursor를 따라가고, 그 커서를 저장하세요.
  2. 초기 상태에 필요한 현재 대화/연락처 목록과 기록을 읽으세요.
  3. 저장한 커서부터 재생해 읽는 동안 생긴 변경을 따라잡으세요. 페이지마다 처리한 뒤 nextCursor를 저장하세요.

이벤트 id로 중복을 제거하세요. 재생은 최소 한 번 전달이므로 후속 작업에도 자체 중복 방지가 필요해요. 커서 없는 요청은 전체 스냅샷이 아니라 최근 1시간을 다뤄요. 이벤트는 30일 동안 보관되며, HTTP 410 resync_required가 오면 처음부터 다시 불러오세요. 범위나 채널 접근 권한을 넓힌 뒤에도 다시 불러오세요. limit은 최대 100, maxBodyChars는 최대 10,000(기본값 500)까지 쓸 수 있어요. compact=true로 설정하면 body/bodyTruncated 대신 200자로 제한된 메시지 textPreview/textTruncated 필드를 받아요. 웹훅으로 에이전트를 깨울 수 있고, 웹훅 구독이 없거나 웹훅 전송이 밀려도 피드는 계속 쓸 수 있어요.

확인 결과를 한 번 기록하고 공유하기

조사를 반복하기 전에 list_conversation_checks(GET /api/v1/conversations/{conversationId}/checks)를 읽으세요. 결과는 record_conversation_check(같은 경로로 PUT)로 저장하며, key, result, checkedBy와 카드 ID나 URL을 위한 선택적 reference를 넣으세요. 예: key=product-version, result=Shopstar Go verified, checkedBy=Engineer, reference=card-X. Sonny가 인증된 actorId와 checkedAt 타임스탬프를 기록해요. 같은 key를 다시 쓰면 그 확인만 바뀌어요. 기록 로그가 아니라 현재 상태예요. 읽기에는 conversations:read, 쓰기에는 conversations:write가 필요하며 둘 다 대화의 채널 범위로 제한돼요. 이 호출은 답장을 보내거나 판매자가 답변한 것으로 표시하지 않아요.

업무를 배정하고 일괄 업데이트하기

GET /api/v1/members and /teams(members:read)로 활성 상태이고 배정 가능한 팀원과 팀을 찾으세요. 응답에는 이메일 주소 없이 응대 가능 상태와 실제 채널 접근 권한이 포함돼요. conversations:write로 status, priority, assigneeId, agentGroupId, snoozedUntil, snoozedUntilReply, addTagIds, removeTagIds를 바꾸세요.

POST /api/v1/conversations/batch
{
  "conversationIds": ["conversation_1", "conversation_2"],
  "updates": { "agentGroupId": "team_1", "assignment": "round_robin" }
}

라운드 로빈은 대화의 채널에 접근할 수 있는 응대 가능한 팀 멤버를 골라요. 해당하는 멤버가 없으면 단일 업데이트는 409를 반환하고 일괄 항목은 실패해요. 일괄 요청마다 고유 ID를 최대 100개 받고, 대화별로 패치 하나를 원자적으로 적용해요. 일부 항목이 실패할 수 있으니 모든 { id, ok, error? } 결과를 확인하세요. 일괄 요청은 항목 수에 따른 가중치 없이 현재 요청 기반 한도를 써요.

Sonny AI와 고객 정보 공유하기

contact-memory:read/write로 연락처 메모리를 나열하고, 저장하고, 제거하세요. contactId와 접근 가능한 sourceId를 모두 넣어야 하며, 연락처에 그 소스의 대화가 있어야 해요. 저장된 사실은 앱과 같은 검증, 중복 처리, 한도를 따르고 수동 메모리로 기록돼요.

/api/v1/properties에서 속성 정의를 읽고, /api/v1/contacts/{contactId}/properties에서 값을 읽거나 설정하세요. MCP는 list_properties, get_contact_properties, set_contact_property를 제공해요. contacts:read/write와 모든 채널 접근 권한이 필요해요. propertyId나 propertyName 중 정확히 하나를 지정하고, 값은 문자열로, 지우려면 null로 보내세요. 텍스트, 숫자, URL, 날짜, 선택 값은 필드 정의에 따라 검증돼요.

PUT /api/v1/contacts/contact_1/properties
{ "propertyName": "Plan", "value": "Pro" }

GET /api/v1/contacts?property[Plan]=Pro

속성 필터는 저장된 문자열과 정확히 일치해야 하며, 여러 속성은 모두 일치해야 해요. API로 작성된 값은 Co-Pilot과 자동 응답기에서 API 데이터로 표시돼요. 기존 인증된 고객 및 소스 규칙은 그대로 적용돼요. 일반적인 수동 내부 필드 값은 이 AI 맥락에서 계속 제외돼요.

팀과 같은 리포트 읽기

reporting:read로 GET /api/v1/reporting/{kind}를 호출하세요. 종류는 overview, volume, response-times, agents, sources, tags, csat, ai, knowledge, leads, online-hours예요. overview는 건수, 응답 시간, CSAT를 합쳐 보여 줘요. 필터는 period(1–365일, 기본값 30), 짝을 이루는 from/to 날짜(to는 제외), granularity(day/month), source, assigneeId, tagId예요. source는 all, all-chat, all-email, website:{id}, email:{id}를 받아요.

리포트는 대시보드와 같은 쿼리와 현재 접근 권한 확인을 사용해요. knowledge는 선택한 소스, 담당자, 태그와 관계없이 날짜와 허용된 채널을 써요. online-hours는 접근 가능한 팀원의 워크스페이스 접속 시간을 측정하고, 대화 수는 채널 범위로 유지돼요. 기존 /csat 엔드포인트는 별도의 csat:read 범위를 유지하며 다른 집단을 기준으로 할 수 있어요.

답장이나 내부 메모와 함께 파일 보내기

attachments:write를 부여하고 대화에 최대 25MB의 파일을 업로드하세요. POST /api/v1/attachments는 multipart file과 conversationId 필드를 받아요. 응답에는 id와 expiresAt이 들어 있어요. 1시간 안에 attachmentIds를 최대 10개까지 답장이나 메모에 넘기세요. 업로드는 내 사용자와 대화에 묶이고 한 번만 쓸 수 있어요. 사용하지 않은 업로드는 만료 후 정리돼요.

POST /api/v1/conversations/conversation_1/reply
{ "attachmentIds": ["upload_1"] }

답장에는 messages:send가, 내부 메모에는 messages:write가 필요하며 내부 메모는 고객에게 절대 전달되지 않아요. 첨부 파일만 있는 메시지도 지원해요. 이메일 답장은 이메일 크기 한도 안에서 파일을 첨부하고 나머지는 다운로드 링크로 넣어요. 오프라인 채팅 이메일에는 파일 링크가 들어가요. 이메일 속 링크는 첨부 파일이 있는 동안 계속 쓸 수 있어 수신자가 나중에 열 수 있어요. 이메일을 전달하면 그 파일에 대한 접근도 공유돼요. 전송 실패는 emailDeliveryStatus로 확인하세요.

권한이 있는 메시지 읽기에는 downloadUrl, downloadExpiresAt, aiStatus, aiDescription, aiExtractedText와 링크된 동영상(Loom, Vimeo 등)의 videoTranscripts가 포함돼요. 다운로드 링크는 15분 동안 유효하며, 새 링크가 필요하면 메시지를 다시 읽으세요. 새 API/MCP 업로드는 비공개 저장소에 저장돼요. 예전 첨부 파일은 공개 상태로 남고 access=legacy_public으로 표시되며, 원래 URL은 만료되지 않아요. 워크스페이스에 Sonny AI가 있으면 메시지를 읽을 때 이미지 판독이 시작돼요. 이미지 판독과 동영상 자막은 메시지 도착 직후 완료돼요. 아직 진행 중인 것이 있으면 응답이 readsInProgress로 시작하고, 그 nextStep에 정확히 어떤 호출을 할지 나와요. waitSeconds(최대 30)를 넘기면 한 번의 요청으로 기다릴 수 있어요. 고객용 위젯과 실시간 메시지에는 추출 결과나 자막이 절대 포함되지 않아요.

전체 요청 및 응답 규격 살펴보기

지식 베이스

외부 소스에서 동기화하기

고정 외부 ID로 아티클과 카테고리를 동기화하고, Markdown이나 HTML을 가져오고, 이미지를 업로드하고, 순서를 정하고, 독자 대상 그룹을 관리하세요. upsert를 반복하면 기존 콘텐츠가 업데이트돼요.

  1. 채널의 sourceId를 고르고 kb:read와 kb:write를 부여하세요. API 키는 서버에 두고 채널 접근 권한을 제한하세요.
  2. 카테고리를 만든 뒤 아티클을 초안으로 동기화하세요. 게시하기 전에 서식과 접근 권한을 검토하세요.
  3. 도움말 센터 접근 권한을 구성하고, 게시하고, 독자 화면을 테스트하세요. 이후 업데이트에는 페이지 나눔과 고정 외부 ID를 쓰세요.
REST 동기화 전체 안내 따라 하기

고객 대상 그룹 관리

인증된 고객 특성으로 그룹을 만들어 도움말 센터, 카테고리, 아티클에 적용하세요. 상속된 모든 제한을 만족해야 해요. API와 MCP 자격 증명은 범위 안에서 직원으로 동작하므로, 독자 접근 권한은 미리보기와 실제 고객 세션으로 테스트하세요.

도움말 센터 대상 그룹 설정하고 테스트하기

관련 문서