얼리어답터 특가2027년 3월 31일까지 유료 플랜 신청 시 3개월간 기본료 50% 할인유료 플랜 3개월 50% 할인D-156자세히 보기
API 연동

API 서버 구현 가이드

AI 상담봇과 잘 맞는 API 를 만드는 규칙과 예제 코드입니다. 이미 있는 API 를 그대로 연결해도 되지만, 챗봇 전용 엔드포인트를 따로 두면 보안과 응답 품질이 좋아집니다.

#응답 규약

  • 요청·응답은 JSON (Content-Type: application/json).
  • HTTP 2xx 이고 본문에 ok: false 가 없으면 성공으로 봅니다.
  • 실패는 { "ok": false, "error": "코드", "message": "고객에게 설명할 문장" }. AI 는 message 를 근거로 고객에게 상황을 설명합니다.
  • 응답은 AI 가 답하는 데 필요한 필드만. 상태 코드 옆에 사람이 읽는 라벨(status_label)을 같이 주면 답변이 정확해집니다.
  • 날짜는 ISO 8601 + 시간대 (2026-09-20T10:12:00+09:00).
{
  "ok": true,
  "order": {
    "order_no": "DM-10001",
    "status": "shipped",
    "status_label": "배송중",
    "items": [{ "name": "텀블러 473ml", "qty": 1 }],
    "total": 24900,
    "shipping": {
      "carrier": "CJ대한통운",
      "tracking_no": "689123456789",
      "tracking_url": "https://trace.cjlogistics.com/…"
    }
  }
}

#서버 보안 체크리스트

  • 키 검증 — 모든 요청에서 헤더의 키를 확인하고, 일치하지 않으면 401.
  • 소유권 재검증 — /customers/{id}/orders/{no} 에서 그 주문이 정말 그 고객의 것인지 서버에서 확인. 처리(dry_run:false) 때도 다시 확인.
  • 최소 데이터 — 전체 주소·전화번호 대신 일부 마스킹(서울시 강남구 ***).
  • 멱등성 — 취소처럼 두 번 호출될 수 있는 처리는 두 번째 호출에서 같은 결과를 주거나 "이미 처리됨" 을 돌려주세요.
  • IP 제한 — 가능하면 클립톡 서버 IP 만 허용.
  • 로그 — 누가(고객 ID) 무엇을 했는지 남기고, 키는 로그에 남기지 마세요.

#예제: Node.js (Express)

본인확인·주문 조회·취소(dry_run) 세 개의 엔드포인트를 가진 최소 예제입니다. 오른쪽 코드를 그대로 복사해 DB 부분만 바꾸면 됩니다.

import express from 'express';
const app = express();
app.use(express.json());

// 1) 키 검증
app.use('/chatbot', (req, res, next) => {
  if (req.get('x-api-key') !== process.env.CHATBOT_API_KEY) {
    return res.status(401).json({ ok: false, error: 'unauthorized', message: '인증 실패' });
  }
  next();
});

// 2) 본인확인
app.post('/chatbot/verify', async (req, res) => {
  const { order_no, phone_last4 } = req.body;
  const order = await db.orders.findOne({ order_no });
  if (!order || order.phone.slice(-4) !== phone_last4) {
    return res.json({ ok: false, error: 'not_found',
      message: '주문번호와 연락처가 일치하는 주문이 없습니다.' });
  }
  const c = await db.customers.findById(order.customer_id);
  res.json({ ok: true, customer: { id: c.id, name: c.name } });
});

// 3) 주문 조회 (소유권 확인)
app.get('/chatbot/customers/:cid/orders/:no', async (req, res) => {
  const o = await db.orders.findOne({ order_no: req.params.no, customer_id: req.params.cid });
  if (!o) return res.status(404).json({ ok: false, error: 'order_not_found', message: '주문을 찾을 수 없습니다.' });
  res.json({ ok: true, order: toChatbotView(o) });
});

// 4) 취소 (dry_run 지원)
app.post('/chatbot/customers/:cid/orders/:no/cancel', async (req, res) => {
  const o = await db.orders.findOne({ order_no: req.params.no, customer_id: req.params.cid });
  if (!o) return res.status(404).json({ ok: false, error: 'order_not_found', message: '주문을 찾을 수 없습니다.' });
  if (!['paid', 'preparing'].includes(o.status)) {
    return res.json({ ok: false, error: 'not_cancellable', message: '이미 발송되어 취소할 수 없습니다.' });
  }
  const summary = [`주문번호: ${o.order_no}`, `환불 예정: ${o.total.toLocaleString()}원`];
  if (req.body.dry_run) return res.json({ ok: true, dry_run: true, summary });
  await cancelOrder(o);
  res.json({ ok: true, status: 'cancelled', message: `주문 ${o.order_no} 이(가) 취소되었습니다.` });
});

app.listen(3000);

#클립톡이 붙이는 오류 코드

error의미
http_<상태>API 가 2xx 가 아닌 상태를 돌려줌 (예: http_404)
bad_json응답이 JSON 이 아님
timeout제한 시간 초과
connector_unreachableDNS·연결·SSL 오류
blocked_address내부망/로컬 주소로 연결되는 도메인
missing_params필수 파라미터 값이 없음
not_verified본인확인 전에 고객 정보가 필요한 작업을 호출
secret_missing참조한 보안키가 저장되지 않음
secret_origin_mismatch보안키가 다른 API 주소용으로 저장됨 (주소 변경 후 재입력 필요)