서문
OpenClaw Gateway는 채팅 채널에 서비스를 제공할 뿐만 아니라 완전한 REST API를 노출합니다. 이러한 API를 통해 AI 기능을 어떤 애플리케이션에든 통합할 수 있습니다. 자체 구축한 웹 프론트엔드, CRM 시스템, 고객 서비스 티켓 플랫폼 등 무엇이든 가능합니다. 본 글에서는 API 사용 방법과 통합 사례를 상세히 소개합니다.
1. API 개요
1.1 기본 정보
| 속성 | 값 |
|---|---|
| 기본 URL | http://localhost:18789/api/v1 |
| 프로토콜 | HTTP/HTTPS |
| 데이터 형식 | JSON |
| 인증 방식 | Bearer Token |
| 속도 제한 | 기본 60 RPM |
1.2 핵심 엔드포인트 목록
| 메서드 | 엔드포인트 | 기능 |
|---|---|---|
| POST | /api/v1/chat |
메시지 전송 및 AI 응답 수신 |
| POST | /api/v1/chat/stream |
스트리밍 메시지 전송 |
| POST | /api/v1/send |
지정 채널로 메시지 전송 |
| GET | /api/v1/conversations |
대화 목록 조회 |
| GET | /api/v1/conversations/:id |
대화 상세 조회 |
| DELETE | /api/v1/conversations/:id |
대화 삭제 |
| GET | /api/v1/skills |
스킬 목록 조회 |
| GET | /api/v1/models |
사용 가능한 모델 목록 조회 |
| GET | /health |
헬스 체크 |
| GET | /health/detail |
상세 상태 |
2. 인증 설정
2.1 API Token 생성
# API Token 생성
openclaw token create --name "my-app" --scope "chat,send,read"
# 출력:
# Token: oc_tok_a1b2c3d4e5f6g7h8i9j0...
# Scope: chat, send, read
# Created: 2026-04-09
# 모든 Token 확인
openclaw token list
# Token 취소
openclaw token revoke oc_tok_a1b2c3d4e5f6g7h8i9j0
2.2 설정 파일에서 설정
// ~/.config/openclaw/openclaw.json5
{
"api": {
"enabled": true,
"port": 18789,
"auth": {
"enabled": true,
"tokens": [
{
"name": "my-web-app",
"token": "oc_tok_a1b2c3d4e5f6g7h8i9j0",
"scope": ["chat", "send", "read", "admin"],
"rateLimit": 120 // RPM
},
{
"name": "crm-integration",
"token": "oc_tok_x9y8z7w6v5u4t3s2r1q0",
"scope": ["chat", "send"],
"rateLimit": 30
}
]
}
}
}
2.3 인증 요청 예시
모든 API 요청은 Header에 Token을 포함해야 합니다:
curl -H "Authorization: Bearer oc_tok_a1b2c3d4e5f6g7h8i9j0" \
http://localhost:18789/api/v1/models
3. 핵심 API 사용
3.1 메시지 전송 및 응답 수신
curl 예시:
curl -X POST http://localhost:18789/api/v1/chat \
-H "Authorization: Bearer $OPENCLAW_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Python으로 퀵소트 알고리즘을 작성해 주세요",
"conversationId": "conv_123",
"model": "claude-sonnet-4-20250514",
"systemPrompt": "당신은 전문 프로그래밍 어시스턴트입니다",
"maxTokens": 2000,
"temperature": 0.7
}'
응답 예시:
{
"id": "msg_abc123",
"conversationId": "conv_123",
"role": "assistant",
"content": "다음은 Python으로 구현한 퀵소트 알고리즘입니다:\n\n```python\ndef quicksort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr) // 2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quicksort(left) + middle + quicksort(right)\n```",
"model": "claude-sonnet-4-20250514",
"usage": {
"inputTokens": 45,
"outputTokens": 156
},
"latency": 2341
}
3.2 스트리밍 출력
curl 예시 (SSE):
curl -X POST http://localhost:18789/api/v1/chat/stream \
-H "Authorization: Bearer $OPENCLAW_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "인공지능에 관한 짧은 글을 작성해 주세요",
"model": "claude-sonnet-4-20250514"
}'
# SSE 이벤트 스트림 반환:
# data: {"type":"start","conversationId":"conv_456"}
# data: {"type":"delta","content":"인공"}
# data: {"type":"delta","content":"지능"}
# data: {"type":"delta","content":"(AI)"}
# ...
# data: {"type":"done","usage":{"inputTokens":20,"outputTokens":350}}
3.3 채널로 메시지 전송
# Telegram 사용자에게 메시지 전송
curl -X POST http://localhost:18789/api/v1/send \
-H "Authorization: Bearer $OPENCLAW_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel": "telegram",
"chatId": "123456789",
"message": "API를 통해 전송된 메시지입니다"
}'
# Discord 채널로 메시지 전송
curl -X POST http://localhost:18789/api/v1/send \
-H "Authorization: Bearer $OPENCLAW_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel": "discord",
"chatId": "CHANNEL_ID",
"message": "시스템 공지: 오늘 밤 22:00부터 서버 유지보수가 시작됩니다"
}'
4. Webhook 수신
4.1 Webhook 콜백 설정
OpenClaw가 메시지를 수신하거나 처리를 완료하면 애플리케이션에 Webhook 알림을 보낼 수 있습니다:
{
"api": {
"webhooks": {
"outgoing": [
{
"url": "https://your-app.com/api/openclaw-callback",
"secret": "your-webhook-secret",
"events": [
"message.received",
"message.sent",
"conversation.created",
"channel.connected",
"channel.disconnected"
],
"retry": {
"maxAttempts": 3,
"backoffMs": 5000
}
}
]
}
}
}
4.2 Webhook 이벤트 형식
{
"event": "message.received",
"timestamp": "2026-04-09T10:30:00Z",
"data": {
"messageId": "msg_xyz789",
"conversationId": "conv_123",
"channel": "telegram",
"chatId": "123456789",
"from": {
"id": "user_456",
"name": "Alice"
},
"content": "사용자가 보낸 메시지 내용",
"timestamp": "2026-04-09T10:30:00Z"
},
"signature": "sha256=abcdef..."
}
4.3 Webhook 서명 검증
import hmac
import hashlib
def verify_webhook(payload, signature, secret):
expected = 'sha256=' + hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
5. Python 통합 예시
5.1 기본 래퍼
import requests
from typing import Optional, Generator
class OpenClawClient:
def __init__(self, base_url: str = "http://localhost:18789",
token: str = ""):
self.base_url = base_url.rstrip("/")
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
def chat(self, message: str, conversation_id: Optional[str] = None,
model: str = "claude-sonnet-4-20250514",
system_prompt: Optional[str] = None) -> dict:
"""메시지를 전송하고 AI 응답을 수신합니다"""
payload = {
"message": message,
"model": model,
}
if conversation_id:
payload["conversationId"] = conversation_id
if system_prompt:
payload["systemPrompt"] = system_prompt
resp = requests.post(
f"{self.base_url}/api/v1/chat",
json=payload,
headers=self.headers,
timeout=120
)
resp.raise_for_status()
return resp.json()
def chat_stream(self, message: str,
model: str = "claude-sonnet-4-20250514") -> Generator:
"""스트리밍으로 메시지를 전송합니다"""
payload = {"message": message, "model": model}
headers = {**self.headers, "Accept": "text/event-stream"}
resp = requests.post(
f"{self.base_url}/api/v1/chat/stream",
json=payload,
headers=headers,
stream=True,
timeout=120
)
resp.raise_for_status()
for line in resp.iter_lines():
if line:
line = line.decode("utf-8")
if line.startswith("data: "):
yield line[6:]
def send(self, channel: str, chat_id: str, message: str) -> dict:
"""지정 채널로 메시지를 전송합니다"""
resp = requests.post(
f"{self.base_url}/api/v1/send",
json={
"channel": channel,
"chatId": chat_id,
"message": message
},
headers=self.headers
)
resp.raise_for_status()
return resp.json()
def health(self) -> dict:
"""헬스 체크"""
resp = requests.get(f"{self.base_url}/health")
return resp.json()
# 사용 예시
client = OpenClawClient(token="oc_tok_a1b2c3d4e5f6g7h8i9j0")
# 일반 대화
result = client.chat("오늘 날씨가 어떤가요?")
print(result["content"])
# 스트리밍 대화
for chunk in client.chat_stream("이야기 하나 해주세요"):
print(chunk, end="", flush=True)
# Telegram으로 전송
client.send("telegram", "123456789", "Hello from API!")
6. Node.js 통합 예시
6.1 기본 래퍼
// openclaw-client.js
const axios = require('axios');
class OpenClawClient {
constructor(baseUrl = 'http://localhost:18789', token = '') {
this.baseUrl = baseUrl;
this.headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
async chat(message, options = {}) {
const { conversationId, model = 'claude-sonnet-4-20250514', systemPrompt } = options;
const payload = { message, model };
if (conversationId) payload.conversationId = conversationId;
if (systemPrompt) payload.systemPrompt = systemPrompt;
const resp = await axios.post(
`${this.baseUrl}/api/v1/chat`,
payload,
{ headers: this.headers, timeout: 120000 }
);
return resp.data;
}
async send(channel, chatId, message) {
const resp = await axios.post(
`${this.baseUrl}/api/v1/send`,
{ channel, chatId, message },
{ headers: this.headers }
);
return resp.data;
}
async health() {
const resp = await axios.get(`${this.baseUrl}/health`);
return resp.data;
}
async getModels() {
const resp = await axios.get(
`${this.baseUrl}/api/v1/models`,
{ headers: this.headers }
);
return resp.data;
}
}
module.exports = OpenClawClient;
// 사용 예시
async function main() {
const client = new OpenClawClient(
'http://localhost:18789',
'oc_tok_a1b2c3d4e5f6g7h8i9j0'
);
// 일반 대화
const result = await client.chat('JavaScript로 피보나치 수열을 구현해 주세요', {
systemPrompt: '당신은 프로그래밍 튜터입니다. 설명은 명확하고 이해하기 쉽게 해주세요'
});
console.log(result.content);
// Discord로 전송
await client.send('discord', 'CHANNEL_ID', 'API에서 보낸 메시지');
// 사용 가능한 모델 조회
const models = await client.getModels();
console.log('사용 가능한 모델:', models);
}
main().catch(console.error);
7. 서드파티 시스템 통합
7.1 CRM 시스템 통합
다음 예시는 OpenClaw를 CRM에 통합하여 고객 피드백을 자동 분석합니다:
# crm_integration.py
from openclaw_client import OpenClawClient
client = OpenClawClient(token="oc_tok_xxx")
def analyze_customer_feedback(feedback_text, customer_id):
"""고객 피드백을 분석하고 분류합니다"""
result = client.chat(
f"다음 고객 피드백을 분석하여 JSON 형식으로 결과를 반환해 주세요:\n\n{feedback_text}",
options={
"systemPrompt": """당신은 고객 피드백 분석 전문가입니다. 피드백을 분류하여 JSON으로 반환해 주세요:
{
"sentiment": "positive/neutral/negative",
"category": "제품 품질/고객 서비스/가격/배송/기타",
"urgency": "high/medium/low",
"summary": "한 줄 요약",
"suggestedAction": "권장 처리 방법"
}"""
}
)
return result["content"]
# 사용
analysis = analyze_customer_feedback(
"제품 품질이 너무 안 좋아요. 구매한 지 이틀 만에 고장 났고, 고객 서비스 태도도 매우 나빴습니다!",
"CUST_001"
)
print(analysis)
7.2 티켓 시스템 통합
# helpdesk_integration.py
def auto_reply_ticket(ticket):
"""자동으로 티켓 초기 응답을 생성합니다"""
result = client.chat(
f"티켓 제목: {ticket['title']}\n"
f"티켓 설명: {ticket['description']}\n"
f"우선순위: {ticket['priority']}\n\n"
f"전문적인 초기 응답을 작성해 주세요.",
options={
"systemPrompt": "당신은 기술 지원 전문가입니다. 티켓 내용을 바탕으로 초기 답변과 처리 권장사항을 제공하세요. 응답은 전문적이고 친절해야 합니다."
}
)
return {
"reply": result["content"],
"auto_generated": True,
"model": result.get("model"),
"needs_review": ticket["priority"] == "high"
}
7.3 자체 구축 웹 프론트엔드
<!-- 간단한 웹 채팅 프론트엔드 -->
<!DOCTYPE html>
<html>
<head>
<title>AI 어시스턴트</title>
<style>
#chat { max-width: 600px; margin: 0 auto; padding: 20px; }
.message { margin: 10px 0; padding: 10px; border-radius: 8px; }
.user { background: #e3f2fd; text-align: right; }
.assistant { background: #f5f5f5; }
#input-area { display: flex; gap: 10px; margin-top: 20px; }
#message-input { flex: 1; padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<div id="chat">
<h2>AI 어시스턴트</h2>
<div id="messages"></div>
<div id="input-area">
<input id="message-input" placeholder="메시지를 입력하세요..." />
<button onclick="sendMessage()">전송</button>
</div>
</div>
<script>
const API_URL = 'http://localhost:18789/api/v1/chat';
const TOKEN = 'oc_tok_a1b2c3d4e5f6g7h8i9j0';
let conversationId = null;
async function sendMessage() {
const input = document.getElementById('message-input');
const message = input.value.trim();
if (!message) return;
appendMessage('user', message);
input.value = '';
try {
const resp = await fetch(API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
message,
conversationId,
model: 'claude-sonnet-4-20250514'
})
});
const data = await resp.json();
conversationId = data.conversationId;
appendMessage('assistant', data.content);
} catch (error) {
appendMessage('assistant', '오류가 발생했습니다: ' + error.message);
}
}
function appendMessage(role, content) {
const div = document.createElement('div');
div.className = `message ${role}`;
div.textContent = content;
document.getElementById('messages').appendChild(div);
div.scrollIntoView({ behavior: 'smooth' });
}
document.getElementById('message-input')
.addEventListener('keydown', e => { if (e.key === 'Enter') sendMessage(); });
</script>
</body>
</html>
8. API 속도 제한
8.1 속도 제한 설정
{
"api": {
"rateLimit": {
// 전역 제한
"global": {
"windowMs": 60000, // 1분 윈도우
"maxRequests": 120 // 최대 120회
},
// Token별 제한
"perToken": {
"windowMs": 60000,
"maxRequests": 60
}
}
}
}
8.2 속도 제한 오류 처리
속도 제한이 발동되면 API가 429 Too Many Requests를 반환합니다:
{
"error": "rate_limit_exceeded",
"message": "요청이 너무 빈번합니다. 잠시 후 다시 시도해 주세요",
"retryAfter": 30
}
클라이언트에서 재시도 로직을 구현합니다:
import time
def chat_with_retry(client, message, max_retries=3):
for attempt in range(max_retries):
try:
return client.chat(message)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
retry_after = int(e.response.headers.get('Retry-After', 30))
print(f"속도 제한 발동, {retry_after}초 후 재시도...")
time.sleep(retry_after)
else:
raise
raise Exception("최대 재시도 횟수 초과")
9. 보안 모범 사례
| 조치 | 설명 |
|---|---|
| HTTPS 사용 | 프로덕션 환경에서는 반드시 Nginx 리버스 프록시를 통해 HTTPS 활성화 |
| Token 권한 최소화 | 필요한 scope만 부여 |
| IP 화이트리스트 | API 접근 출처 제한 |
| 입력 검증 | 사용자 입력 정리, 프롬프트 인젝션 방지 |
| 로그 감사 | 모든 API 호출 기록 |
| 정기 Token 교체 | 90일마다 교체 |
{
"api": {
"security": {
// IP 화이트리스트
"allowedIPs": ["10.0.0.0/8", "192.168.1.0/24"],
// CORS 설정
"cors": {
"enabled": true,
"origins": ["https://your-app.com"],
"methods": ["GET", "POST", "DELETE"]
},
// 요청 본문 크기 제한
"maxBodySize": "1MB"
}
}
}
10. 디버깅 및 문제 해결
# API 요청 로그 확인
openclaw logs | grep -i "api\|request\|response"
# verbose curl로 디버깅
curl -v -X POST http://localhost:18789/api/v1/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"test"}'
# API 서비스 상태 확인
curl -s http://localhost:18789/health | jq .
위의 API 통합 방안을 통해 OpenClaw의 AI 기능을 기존 시스템에 원활하게 통합하여 강력한 지능형 애플리케이션을 구축할 수 있습니다.